oxarticle.php

Go to the documentation of this file.
00001 <?php
00002 
00003 // defining supported link types
00004 define( 'OXARTICLE_LINKTYPE_CATEGORY', 0 );
00005 define( 'OXARTICLE_LINKTYPE_VENDOR', 1 );
00006 define( 'OXARTICLE_LINKTYPE_MANUFACTURER', 2 );
00007 define( 'OXARTICLE_LINKTYPE_PRICECATEGORY', 3 );
00008 define( 'OXARTICLE_LINKTYPE_TAG', 4 );
00009 
00016 class oxArticle extends oxI18n implements oxIArticle
00017 {
00023     protected $_sCoreTbl = 'oxarticles';
00024 
00030     protected $_sClassName = 'oxarticle';
00031 
00037     protected $_blUseLazyLoading = true;
00038 
00044     protected $_sItemKey;
00045 
00051     protected $_blCalcPrice    = true;
00052 
00057     protected $_oPrice      = null;
00058 
00064     protected $_dArticleVat = null;
00065 
00071     protected $_aPersistParam  = null;
00072 
00078     protected $_blNotBuyable   = false;
00079 
00086     protected $_blLoadVariants = true;
00087 
00093     protected $_aVariants = null;
00094 
00100     protected $_aVariantsWithNotOrderables = null;
00101 
00110     protected $_blNotBuyableParent  = false;
00111 
00116     protected $_blHasVariants = false;
00117 
00121     protected $_iVarStock = 0;
00122 
00127     protected $_oVariantList   = array();
00128 
00133     protected $_blIsOnComparisonList = false;
00134 
00139     protected $_oUser = null;
00140 
00146     protected $_blLoadPrice = true;
00147 
00151     protected $_blSkipAbPrice = false;
00152 
00159     protected $_fPricePerUnit = null;
00160 
00164     protected $_blLoadParentData = false;
00165 
00169     protected $_blSkipAssign = false;
00170 
00176     protected $_blSkipDiscounts = null;
00177 
00182     protected $_oAttributeList = null;
00183 
00184 
00190     protected $_blIsRangePrice = false;
00191 
00197     protected $_aMediaUrls = null;
00198 
00204     static protected $_aLoadedParents;
00205 
00211     static protected $_aSelList;
00212 
00218     protected $_aDispSelList;
00219 
00225     protected $_blIsSeoObject = true;
00226 
00232     protected $_oAmountPriceList = null;
00233 
00242     protected $_iLinkType = 0;
00243 
00249     protected $_sStdLink = null;
00250 
00256     protected $_sDynImageDir = null;
00257 
00263     protected $_sMoreDetailLink = null;
00264 
00270     protected $_sToBasketLink = null;
00271 
00277     protected $_iStockStatus = null;
00278 
00284     protected $_oTPrice = null;
00285 
00291     protected $_oAmountPriceInfo = null;
00292 
00298     protected $_dAmountPrice = null;
00299 
00305     protected $_sDetailLink = null;
00306 
00312     protected static $_aArticleManufacturers = array();
00313 
00319     protected static $_aArticleVendors = array();
00320 
00326     protected static $_aArticleCats = array();
00327 
00336     public function __construct($aParams = null)
00337     {
00338         if ( $aParams && is_array($aParams)) {
00339             foreach ( $aParams as $sParam => $mValue) {
00340                 $this->$sParam = $mValue;
00341             }
00342         }
00343         parent::__construct();
00344         $this->init( 'oxarticles' );
00345 
00346         $this->_blIsRangePrice = false;
00347     }
00348 
00356     public function __isset( $sName )
00357     {
00358         if ( $sName == 'oxarticles__oxlongdesc' ) {
00359             //get empty oxlongdesc field
00360             $this->getArticleLongDesc();
00361             return true;
00362         }
00363         return isset( $this->$sName );
00364     }
00365 
00374     public function __get($sName)
00375     {
00376         $myUtils = oxUtils::getInstance();
00377         switch ($sName) {
00378             // NOT using caching here, because of these params should be used in templates ONLY
00379             // and in template files they are used not very much [once most of the time]
00380 
00381             // price related
00382             case 'netprice':
00383             case 'netPrice':
00384                 $mVal = $myUtils->fRound($this->getPrice()->getNettoPrice());
00385                 break;
00386             case 'brutPrice':
00387                 return $myUtils->fRound($this->getPrice()->getBruttoPrice());
00388                 break;
00389             case 'vatPercent':
00390                 return $this->getPrice()->getVAT();
00391                 break;
00392             case 'vat':
00393                 return $this->getPrice()->getVATValue();
00394                 break;
00395             case 'fnetprice':
00396                 return oxLang::getInstance()->formatCurrency( $myUtils->fRound($this->getPrice()->getNettoPrice()));
00397                 break;
00398             case 'fprice':
00399                 return $this->getFPrice();
00400                 break;
00401 
00402             // t price related
00403             case 'dtprice':
00404                 if ( $oPrice = $this->getTPrice() ) {
00405                     return $myUtils->fRound($oPrice->getBruttoPrice());
00406                     break;
00407                 } else {
00408                     return null;
00409                     break;
00410                 }
00411             case 'tvat':
00412                 if ( $oPrice = $this->getTPrice() ) {
00413                     return $oPrice->getVATValue();
00414                     break;
00415                 } else {
00416                     return null;
00417                     break;
00418                 }
00419             case 'ftprice':
00420                 if ( $oPrice = $this->getTPrice() ) {
00421                     return oxLang::getInstance()->formatCurrency( $myUtils->fRound($oPrice->getBruttoPrice()) );
00422                     break;
00423                 } else {
00424                     return null;
00425                     break;
00426                 }
00427             case 'oxarticles__oxlongdesc':
00428                 return $this->getArticleLongDesc($this->getId());
00429                 break;
00430             case 'foxdelivery':
00431                 return $this->getDeliveryDate();
00432                 break;
00433             case 'sItemKey':
00434                 return $this->getItemKey();
00435                 break;
00436             case 'selectlist':
00437                 return $this->_aDispSelList = $this->getDispSelList();
00438                 break;
00439             case 'blNotBuyable':
00440                 return $this->isNotBuyable();
00441                 break;
00442             case 'blNotBuyableParent':
00443                 return $this->isParentNotBuyable();
00444                 break;
00445             case 'blIsOnComparisonList':
00446                 return $this->isOnComparisonList();
00447                 break;
00448             case 'oVariantlist' :
00449                 return $this->_oVariantList;
00450                 break;
00451             case 'fPricePerUnit' :
00452                 return $this->getPricePerUnit();
00453                 break;
00454             case 'dimagedir' :
00455                 return $this->_sDynImageDir = $this->getDynImageDir();
00456                 break;
00457             case 'oxmoredetaillink' :
00458                 return $this->_sMoreDetailLink = $this->getMoreDetailLink();
00459                 break;
00460             case 'amountpricelist' :
00461                 return $this->loadAmountPriceInfo();
00462                 break;
00463             case 'stockstatus' :
00464                 return $this->getStockStatus();
00465                 break;
00466             case 'tobasketlink' :
00467                 return $this->getToBasketLink();
00468                 break;
00469             case 'oxdetaillink' :
00470                 return $this->getLink();
00471                 break;
00472             /*case 'oxarticles__oxnid':
00473                 return $this->getId();*/
00474         }
00475 
00476         $sRet = parent::__get($sName);
00477         if ( $this->$sName ) {
00478             $this->_assignParentFieldValue($sName);
00479         }
00480         //checking for picture information
00481         if ($sName == "oxarticles__oxthumb" || $sName == "oxarticles__oxicon" || strpos($sName, "oxarticles__oxpic") === 0 || strpos($sName, "oxarticles__oxzoom") === 0) {
00482             $this->_assignPictureValues();
00483             return $this->$sName;
00484         }
00485 
00486         return $sRet;
00487     }
00488 
00496     public function setId( $sId = null )
00497     {
00498         $sId = parent::setId( $sId );
00499 
00500         // TODO: in oxbase::setId make it to check if exists and update, not recreate, then delete this overload
00501         $this->oxarticles__oxnid = $this->oxarticles__oxid;
00502 
00503         return $sId;
00504     }
00505 
00513     public function getSqlActiveSnippet( $blForceCoreTable = false )
00514     {
00515         $myConfig = $this->getConfig();
00516             $sTable = $this->getCoreTableName();
00517 
00518         // check if article is still active
00519         $sQ = " $sTable.oxactive = 1 ";
00520 
00521         // enabled time range check ?
00522         if ( $myConfig->getConfigParam( 'blUseTimeCheck' ) ) {
00523             $sDate = date( 'Y-m-d H:i:s', oxUtilsDate::getInstance()->getTime() );
00524             $sQ = "( $sQ or ( $sTable.oxactivefrom < '$sDate' and $sTable.oxactiveto > '$sDate' ) ) ";
00525         }
00526 
00527         //do not check for variants
00528         if ( $myConfig->getConfigParam( 'blUseStock' ) ) {
00529             $sQ = " $sQ and ( $sTable.oxstockflag != 2 or ( $sTable.oxstock + $sTable.oxvarstock ) > 0  ) ";
00530             //V #M513: When Parent article is not purchaseble, it's visibility should be displayed in shop only if any of Variants is available.
00531             if ( !$myConfig->getConfigParam( 'blVariantParentBuyable' ) ) {
00532                 $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 ) ";
00533             }
00534         }
00535 
00536 
00537         return "( $sQ ) ";
00538     }
00539 
00547     public function setSkipAssign($blSkipAssign)
00548     {
00549         $this->_blSkipAssign = $blSkipAssign;
00550     }
00551 
00559     public function disablePriceLoad( $oArticle )
00560     {
00561         $oArticle->_blLoadPrice = false;
00562     }
00563 
00569     public function getItemKey()
00570     {
00571         return $this->_sItemKey;
00572     }
00573 
00581     public function setItemKey($sItemKey)
00582     {
00583         $this->_sItemKey = $sItemKey;
00584     }
00585 
00593     public function setNoVariantLoading( $blLoadVariants )
00594     {
00595         $this->_blLoadVariants = !$blLoadVariants;
00596     }
00597 
00603     public function isBuyable()
00604     {
00605         if ($this->_blNotBuyableParent) {
00606             return false;
00607         }
00608 
00609         return !$this->_blNotBuyable;
00610     }
00611 
00617     public function getPersParams()
00618     {
00619         return $this->_aPersistParam;
00620     }
00621 
00627     public function isOnComparisonList()
00628     {
00629         return $this->_blIsOnComparisonList;
00630     }
00631 
00639     public function setOnComparisonList( $blOnList )
00640     {
00641         $this->_blIsOnComparisonList = $blOnList;
00642     }
00643 
00651     public function setLoadParentData($blLoadParentData)
00652     {
00653         $this->_blLoadParentData = $blLoadParentData;
00654     }
00655 
00663     public function setSkipAbPrice( $blSkipAbPrice = null )
00664     {
00665         $this->_blSkipAbPrice = $blSkipAbPrice;
00666     }
00667 
00673     public function getSearchableFields()
00674     {
00675         $aSkipFields = array("oxblfixedprice", "oxicon", "oxvarselect", "oxamitemid", "oxamtaskid", "oxpixiexport", "oxpixiexported") ;
00676         $aFields = array_diff( array_keys($this->_aFieldNames), $aSkipFields );
00677 
00678         return $aFields;
00679     }
00680 
00681 
00689     public function isMultilingualField($sFieldName)
00690     {
00691         if ($sFieldName == "oxlongdesc") {
00692             return true;
00693         }
00694 
00695         return parent::isMultilingualField($sFieldName);
00696     }
00697 
00703     public function isVisible()
00704     {
00705 
00706         // admin preview mode
00707         $myConfig  = $this->getConfig();
00708         if ( ( $sPrevId = oxConfig::getParameter( 'preview' ) ) &&
00709              ( $sAdminSid = oxUtilsServer::getInstance()->getOxCookie( 'admin_sid' ) ) ) {
00710 
00711             $oDb = oxDb::getDb();
00712             $sPrevId   = $oDb->quote( $sPrevId );
00713             $sAdminSid = $oDb->quote( $sAdminSid );
00714             $sTable    = getViewName( 'oxuser' );
00715 
00716             return (bool) $oDb->getOne( "select 1 from $sTable where MD5( CONCAT( {$sAdminSid}, {$sTable}.oxid, {$sTable}.oxpassword, {$sTable}.oxrights ) ) = $sPrevId" );
00717         }
00718 
00719         // active ?
00720         $sNow = date('Y-m-d H:i:s');
00721         if ( !$this->oxarticles__oxactive->value &&
00722              (  $this->oxarticles__oxactivefrom->value > $sNow ||
00723                 $this->oxarticles__oxactiveto->value < $sNow
00724              )) {
00725             return false;
00726         }
00727 
00728         // stock flags
00729         if ( $myConfig->getConfigParam( 'blUseStock' ) && $this->oxarticles__oxstockflag->value == 2 &&
00730            ( $this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value ) <= 0 ) {
00731             return false;
00732         }
00733 
00734         return true;
00735     }
00736 
00745     public function assign( $aRecord)
00746     {
00747         startProfile('articleAssign');
00748 
00749 
00750         // load object from database
00751         parent::assign( $aRecord);
00752 
00753         $this->oxarticles__oxnid = $this->oxarticles__oxid;
00754 
00755         // check for simple article.
00756         if ($this->_blSkipAssign) {
00757             return;
00758         }
00759 
00760         $this->_assignParentFieldValues();
00761         $this->_assignNotBuyableParent();
00762         $this->_assignPictureValues();
00763         $this->_assignStock();
00764         startProfile('articleAssignPrices');
00765         $this->_assignPrices();
00766         stopProfile('articleAssignPrices');
00767         $this->_assignPersistentParam();
00768         $this->_assignDynImageDir();
00769         $this->_assignComparisonListFlag();
00770         $this->_assignAttributes();
00771 
00772 
00773         //$this->_seoAssign();
00774 
00775         stopProfile('articleAssign');
00776     }
00777 
00788     public function load( $oxID)
00789     {
00790         // A. #1325 resetting to avoid problems when reloading (details etc)
00791         $this->_blNotBuyableParent = false;
00792 
00793         $blRet = parent::load( $oxID);
00794 
00795         // convert date's to international format
00796         $this->oxarticles__oxinsert    = new oxField(oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxinsert->value));
00797         $this->oxarticles__oxtimestamp = new oxField(oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxtimestamp->value));
00798 
00799         return $blRet;
00800     }
00801 
00809     public function addToRatingAverage( $iRating)
00810     {
00811         $dOldRating = $this->oxarticles__oxrating->value;
00812         $dOldCnt    = $this->oxarticles__oxratingcnt->value;
00813         $this->oxarticles__oxrating->setValue(( $dOldRating * $dOldCnt + $iRating ) / ($dOldCnt + 1));
00814         $this->oxarticles__oxratingcnt->setValue($dOldCnt + 1);
00815         $dRating = ( $dOldRating * $dOldCnt + $iRating ) / ($dOldCnt + 1);
00816         $dRatingCnt = $dOldCnt + 1;
00817         // oxarticles.oxtimestamp = oxarticles.oxtimestamp to keep old timestamp value
00818         oxDb::getDb()->execute( 'update oxarticles set oxarticles.oxrating = '.$dRating.',oxarticles.oxratingcnt = '.$dRatingCnt.', oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = "'.$this->getId().'" ' );
00819     }
00820 
00826     public function getArticleRatingAverage()
00827     {
00828         return round( $this->oxarticles__oxrating->value, 1);
00829     }
00830 
00836     public function getReviews()
00837     {
00838         $myConfig  = $this->getConfig();
00839 
00840         $aIds = array($this->getId());
00841 
00842         if ( $this->oxarticles__oxparentid->value ) {
00843                 $aIds[] = $this->oxarticles__oxparentid->value;
00844         }
00845 
00846         // showing variant reviews ..
00847         if ( $myConfig->getConfigParam( 'blShowVariantReviews' ) ) {
00848             $aAdd = $this->_getVariantsIds();
00849             if (is_array($aAdd)) {
00850                 $aIds = array_merge($aIds, $aAdd);
00851             }
00852         }
00853 
00854         $oReview = oxNew('oxreview');
00855         $oRevs = $oReview->loadList('oxarticle', $aIds);
00856 
00857         //if no review found, return null
00858         if ( $oRevs->count() < 1 ) {
00859             return null;
00860         }
00861 
00862         return $oRevs;
00863     }
00864 
00870     public function getCrossSelling()
00871     {
00872         $oCrosslist = oxNew( "oxarticlelist");
00873         $oCrosslist->loadArticleCrossSell($this->oxarticles__oxid->value);
00874         if ( $oCrosslist->count() ) {
00875             return $oCrosslist;
00876         }
00877     }
00878 
00884     public function getAccessoires()
00885     {
00886         $myConfig = $this->getConfig();
00887 
00888         // Performance
00889         if ( !$myConfig->getConfigParam( 'bl_perfLoadAccessoires' ) ) {
00890             return;
00891         }
00892 
00893         $oAcclist = oxNew( "oxarticlelist");
00894         $oAcclist->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofCrossellArticles' ));
00895         $oAcclist->loadArticleAccessoires($this->oxarticles__oxid->value);
00896 
00897         if ( $oAcclist->count()) {
00898             return $oAcclist;
00899         }
00900     }
00901 
00907     public function getSimilarProducts()
00908     {
00909         // Performance
00910         $myConfig = $this->getConfig();
00911         if ( !$myConfig->getConfigParam( 'bl_perfLoadSimilar' ) ) {
00912             return;
00913         }
00914 
00915         $sArticleTable = $this->_getObjectViewName('oxarticles');
00916 
00917         $sAttribs = '';
00918         $iCnt = 0;
00919         $this->_getAttribsString($sAttribs, $iCnt);
00920 
00921         if ( !$sAttribs) {
00922             return null;
00923         }
00924 
00925         // DODGER : Actually to optimize this function we only take the similar products from the first 100 hits
00926         // I think that this is possible as this function anyway never worked like it should
00927         // Calculation of iHitMin was ALWAYS == 1
00928         // 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
00929 
00930         $aList = $this->_getSimList($sAttribs, $iCnt);
00931 
00932         if ( count( $aList ) ) {
00933             uasort( $aList, 'cmpart');
00934 
00935             $sSearch = $this->_generateSimListSearchStr($sArticleTable, $aList);
00936 
00937             $oSimilarlist = oxNew( 'oxarticlelist' );
00938             $oSimilarlist->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofSimilarArticles' ));
00939             $oSimilarlist->selectString( $sSearch);
00940 
00941             return $oSimilarlist;
00942         }
00943     }
00944 
00950     public function getCustomerAlsoBoughtThisProducts()
00951     {
00952         // Performance
00953         $myConfig = $this->getConfig();
00954         if ( !$myConfig->getConfigParam( 'bl_perfLoadCustomerWhoBoughtThis' ) ) {
00955             return;
00956         }
00957 
00958         // selecting products that fits
00959         $sQ = $this->_generateSearchStrForCustomerBought();
00960 
00961         $oArticles = oxNew( 'oxarticlelist' );
00962         $oArticles->setSqlLimit( 0, $myConfig->getConfigParam( 'iNrofCustomerWhoArticles' ));
00963         $oArticles->selectString( $sQ );
00964         if ( $oArticles->count() ) {
00965             return $oArticles;
00966         }
00967     }
00968 
00975     public function loadAmountPriceInfo()
00976     {
00977         $myConfig = $this->getConfig();
00978         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice || !$this->_blCalcPrice) {
00979             return array();
00980         }
00981 
00982         if ( $this->_oAmountPriceInfo !== null ) {
00983             return $this->_oAmountPriceInfo;
00984         }
00985 
00986         $oAmPriceList = $this->_getAmountPriceList();
00987 
00988         if ( count( $oAmPriceList ) ) {
00989             $this->_oAmountPriceInfo = $this->_fillAmountPriceList( $oAmPriceList );
00990             return $this->_oAmountPriceInfo;
00991         }
00992 
00993         return array();
00994     }
00995 
01003     public function getSelectLists($sKeyPrefix = null)
01004     {
01005         //#1468C - more then one article in basket with different selectlist...
01006         //optionall function parameter $sKeyPrefix added, used only in basket.php
01007         $sKey = $this->getId();
01008         if ( isset( $sKeyPrefix ) ) {
01009             $sKey = $sKeyPrefix.'__'.$this->getId();
01010         }
01011 
01012         if ( self::$_aSelList[$sKey]) {
01013             return self::$_aSelList[$sKey];
01014         }
01015 
01016         // all selectlists this article has
01017         $oLists = oxNew( 'oxlist' );
01018         $oLists->init('oxselectlist');
01019         $sSLViewName = getViewName('oxselectlist');
01020         $sSelect  = "select $sSLViewName.* from oxobject2selectlist left join $sSLViewName on $sSLViewName.oxid=oxobject2selectlist.oxselnid ";
01021         $sSelect .= 'where oxobject2selectlist.oxobjectid=\''.$this->getId().'\' ';
01022         //sorting
01023         $sSelect .= ' order by oxobject2selectlist.oxsort';
01024 
01025         $oLists->selectString( $sSelect );
01026 
01027         //#1104S if this is variant ant it has no selectlists, trying with parent
01028         if ( $this->oxarticles__oxparentid->value && $oLists->count() == 0 ) {
01029             //#1496C - select fixed ( * => $sSLViewName.*)
01030             $sSelect  = "select $sSLViewName.* from oxobject2selectlist left join $sSLViewName on $sSLViewName.oxid=oxobject2selectlist.oxselnid ";
01031             $sSelect .= "where oxobject2selectlist.oxobjectid='{$this->oxarticles__oxparentid->value}' ";
01032             //sorting
01033             $sSelect .= ' order by oxobject2selectlist.oxsort';
01034             $oLists->selectString( $sSelect);
01035         }
01036 
01037         $dVat = 0;
01038         if ( $this->getPrice() != null ) {
01039             $dVat = $this->getPrice()->getVat();
01040         }
01041 
01042         $iCnt = 0;
01043         self::$_aSelList[$sKey] = array();
01044         foreach ( $oLists as $oSelectlist ) {
01045             self::$_aSelList[$sKey][$iCnt] = $oSelectlist->getFieldList( $dVat );
01046             self::$_aSelList[$sKey][$iCnt]['name'] = $oSelectlist->oxselectlist__oxtitle->value;
01047             $iCnt++;
01048         }
01049         return self::$_aSelList[$sKey];
01050     }
01051 
01059     public function getVariants( $blRemoveNotOrderables = true )
01060     {
01061         if ($blRemoveNotOrderables && $this->_aVariants) {
01062             return $this->_aVariants;
01063         } elseif (!$blRemoveNotOrderables && $this->_aVariantsWithNotOrderables) {
01064             return $this->_aVariantsWithNotOrderables;
01065         }
01066 
01067         if (!$this->_blLoadVariants) {
01068             return array();
01069         }
01070 
01071         $myConfig = $this->getConfig();
01072 
01073         // Performance
01074         if ( !$this->isAdmin() && !$myConfig->getConfigParam( 'blLoadVariants')) {
01075             return array();
01076         }
01077 
01078         //do not load variants where variant oxvarcount is 0
01079         //hint: if variantas are not loaded you should check your data integrity oxvarcount should always be equal to variant count
01080         if (!$this->isAdmin() && !$this->oxarticles__oxvarcount->value) {
01081             return array();
01082         }
01083 
01084         //do not load me as a parent later
01085         self::$_aLoadedParents[$this->getId()] = $this;
01086 
01087         //load simple variants for lists
01088         if ($this->_isInList()) {
01089             $oVariants = oxNew( 'oxsimplevariantlist' );
01090             $oVariants->setParent($this);
01091         } else {
01092             //loading variants
01093             $oVariants = oxNew( 'oxarticlelist' );
01094             $oVariants->getBaseObject()->modifyCacheKey('_variants');
01095         }
01096 
01097         startProfile("selectVariants");
01098         $sSelectFields = $oVariants->getBaseObject()->getSelectFields();
01099         $sArticleTable = $this->getViewName();
01100         $sSelect =  "select $sSelectFields from $sArticleTable where ";
01101         $sSelect .= " $sArticleTable.oxparentid ='".$this->getId()."' ";
01102         $sSelect .= " order by $sArticleTable.oxsort";
01103         $oVariants->selectString( $sSelect);
01104         stopProfile("selectVariants");
01105 
01106         if (!$oVariants->count()) {
01107             return array();
01108         }
01109         $oVariants = $this->_removeInactiveVariants( $oVariants, $blRemoveNotOrderables );
01110         //$this->calculateMinVarPrice($oVariants);
01111         //#1104S Load selectlists
01112         if ( $myConfig->getConfigParam( 'bl_perfLoadSelectLists' ) ) {
01113             foreach ($oVariants as $key => $oVariant) {
01114                 $oVariants[$key]->aSelectlist = $oVariant->getSelectLists();
01115             }
01116         }
01117         if ( $blRemoveNotOrderables ) {
01118             $this->_aVariants = $oVariants;
01119         } else {
01120             $this->_aVariantsWithNotOrderables = $oVariants;
01121         }
01122 
01123         return $oVariants;
01124     }
01125 
01131     public function getSimpleVariants()
01132     {
01133         if ( $this->oxarticles__oxvarcount->value) {
01134             return $this->getVariants();
01135         }
01136     }
01137 
01146     public function getAdminVariants( $sLanguage = null )
01147     {
01148         $myConfig = $this->getConfig();
01149 
01150         $oVariants = oxNew( 'oxarticlelist');
01151 
01152         if ( is_null($sLanguage) ) {
01153             $oVariants->getBaseObject()->setLanguage(oxLang::getInstance()->getBaseLanguage());
01154         } else {
01155             $oVariants->getBaseObject()->setLanguage($sLanguage);
01156         }
01157 
01158         $sSql = 'select * from oxarticles where oxparentid = "'.$this->getId().'" order by oxsort ';
01159 
01160         $oVariants->selectString( $sSql);
01161 
01162         //if we have variants then depending on config option the parent may be non buyable
01163         if (!$myConfig->getConfigParam( 'blVariantParentBuyable' ) && ($oVariants->count() > 0)) {
01164             //$this->blNotBuyable = true;
01165             $this->_blNotBuyableParent = true;
01166         }
01167 
01168         return $oVariants;
01169     }
01170 
01178     public function getCategory()
01179     {
01180         startPRofile( 'getCategory' );
01181 
01182         $oCategory = oxNew( 'oxcategory' );
01183         $oCategory->setLanguage( $this->getLanguage() );
01184 
01185         // variant handling
01186         $sOXID = $this->getId();
01187         if ( isset( $this->oxarticles__oxparentid->value ) && $this->oxarticles__oxparentid->value ) {
01188             $sOXID = $this->oxarticles__oxparentid->value;
01189         }
01190 
01191         $oStr = getStr();
01192         $sWhere   = $oCategory->getSqlActiveSnippet();
01193         $sSelect  = $this->_generateSearchStr( $sOXID );
01194         $sSelect .= ( $oStr->strstr( $sSelect, 'where' )?' and ':' where ') . $sWhere . " order by oxobject2category.oxtime ";
01195 
01196         // category not found ?
01197         if ( !$oCategory->assignRecord( $sSelect ) ) {
01198 
01199             $sSelect  = $this->_generateSearchStr( $sOXID, true );
01200             $sSelect .= ( $oStr->strstr( $sSelect, 'where' )?' and ':' where ') . $sWhere ;
01201 
01202             // looking for price category
01203             if ( !$oCategory->assignRecord( $sSelect ) ) {
01204                 $oCategory = null;
01205             }
01206         }
01207 
01208         stopPRofile( 'getCategory' );
01209         return $oCategory;
01210     }
01211 
01219     public function getCategoryIds( $blSkipCache = false )
01220     {
01221         $myConfig = $this->getConfig();
01222         if ( isset( self::$_aArticleCats[$this->getId()] ) && !$blSkipCache ) {
01223             return self::$_aArticleCats[$this->getId()];
01224         }
01225 
01226         // variant handling
01227         $sOXID = $this->getId();
01228         if (isset( $this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01229             $sOXID = $this->oxarticles__oxparentid->value;
01230         }
01231 
01232         $sO2CView = $this->_getObjectViewName('oxobject2category');
01233         $sCatView = $this->_getObjectViewName('oxcategories');
01234 
01235         // we do not use lists here as we dont need this overhead right now
01236         $oDB = oxDb::getDb(true);
01237         $sSelect =  "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
01238         $sSelect .= 'where oxobject2category.oxobjectid=\''.$sOXID.'\' and oxcategories.oxid is not null and oxcategories.oxactive'.(($this->getLanguage())?'_'.$this->getLanguage():'').' = 1 order by oxobject2category.oxtime ';
01239         $rs = $oDB->execute( $sSelect);
01240 
01241 
01242         $aRet = array();
01243         $iHitMax = 0;
01244         if ($rs != false && $rs->recordCount() > 0) {
01245             while (!$rs->EOF) {
01246                 $aRet[] = $rs->fields['oxcatnid'];
01247                 $rs->moveNext();
01248             }
01249         }
01250 
01251         return self::$_aArticleCats[$this->getId()] = $aRet;
01252     }
01253 
01263     public function getVendor( $blShopCheck = true )
01264     {
01265         if ( ( $sVendorId = $this->getVendorId() ) ) {
01266             $oVendor = oxNew( 'oxvendor' );
01267         } elseif ( !$blShopCheck && $this->oxarticles__oxvendorid->value ) {
01268             $oVendor = oxNew( 'oxi18n' );
01269             $oVendor->init('oxvendor');
01270             $oVendor->setReadOnly( true );
01271             $sVendorId = $this->oxarticles__oxvendorid->value;
01272         }
01273         if ( $sVendorId && $oVendor->load( $sVendorId ) && $oVendor->oxvendor__oxactive->value ) {
01274             if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadVendorTree' ) ) {
01275                 $oVendor->setReadOnly( true );
01276             }
01277             return $oVendor;
01278         }
01279         return null;
01280     }
01281 
01289     public function getVendorId( $blForceReload = false )
01290     {
01291         $sVendorId = false;
01292         if ( $this->oxarticles__oxvendorid->value ) {
01293             if ( !$blForceReload && isset( self::$_aArticleVendors[$this->getId()] ) ) {
01294                 return self::$_aArticleVendors[$this->getId()];
01295             }
01296             $sQ = "select oxid from ".getViewName('oxvendor')." where oxid='{$this->oxarticles__oxvendorid->value}'";
01297             self::$_aArticleVendors[$this->getId()] = $sVendorId = oxDb::getDb()->getOne( $sQ );
01298         }
01299         return $sVendorId;
01300     }
01301 
01309     public function getManufacturerId( $blForceReload = false )
01310     {
01311         $sManufacturerId = false;
01312         if ( $this->oxarticles__oxmanufacturerid->value ) {
01313             if ( !$blForceReload && isset( self::$_aArticleManufacturers[$this->getId()])) {
01314                 return self::$_aArticleManufacturers[$this->getId()];
01315             }
01316             $sQ = "select oxid from ".getViewName('oxmanufacturers')." where oxid='{$this->oxarticles__oxmanufacturerid->value}'";
01317             self::$_aArticleManufacturers[$this->getId()] = $sManufacturerId = oxDb::getDb()->getOne( $sQ );
01318         }
01319         return $sManufacturerId;
01320     }
01321 
01331     public function getManufacturer( $blShopCheck = true )
01332     {
01333         $oManufacturer = null;
01334         if ( ( $sManufacturerId = $this->getManufacturerId() ) ) {
01335             $oManufacturer = oxNew( 'oxmanufacturer' );
01336         } elseif ( !$blShopCheck && $this->oxarticles__oxmanufacturerid->value ) {
01337             $oManufacturer = oxNew( 'oxI18n' );
01338             $oManufacturer->init('oxmanufacturers');
01339             $oManufacturer->setReadOnly( true );
01340             $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
01341         }
01342 
01343         if ( $sManufacturerId && $oManufacturer->load( $sManufacturerId ) ) {
01344             if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadManufacturerTree' ) ) {
01345                 $oManufacturer->setReadOnly( true );
01346             }
01347             $oManufacturer = $oManufacturer->oxmanufacturers__oxactive->value ? $oManufacturer : null;
01348         } else {
01349             $oManufacturer = null;
01350         }
01351 
01352         return $oManufacturer;
01353     }
01354 
01363     public function inCategory( $sCatNid)
01364     {
01365         return in_array( $sCatNid, $this->getCategoryIds());
01366     }
01367 
01376     public function isAssignedToCategory( $sCatId )
01377     {
01378         // variant handling
01379         $sOXID = $this->getId();
01380         if ( isset( $this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01381             $sOXID = $this->oxarticles__oxparentid->value;
01382         }
01383 
01384         $oDB = oxDb::getDb();
01385         $sSelect = $this->_generateSelectCatStr( $sOXID, $sCatId);
01386         $sOXID = $oDB->getOne( $sSelect);
01387         // article is assigned to passed category!
01388         if ( isset( $sOXID) && $sOXID) {
01389             return true;
01390         }
01391 
01392         // maybe this category is price category ?
01393         if ( $this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) && $this->_blLoadPrice ) {
01394             $dPriceFromTo = $this->getPrice()->getBruttoPrice();
01395             if ( $dPriceFromTo > 0) {
01396                 $sSelect = $this->_generateSelectCatStr( $sOXID, $sCatId, $dPriceFromTo);
01397                 $sOXID = $oDB->getOne( $sSelect);
01398                 // article is assigned to passed category!
01399                 if ( isset( $sOXID) && $sOXID) {
01400                     return true;
01401                 }
01402             }
01403         }
01404         return false;
01405     }
01406 
01412     public function getTPrice()
01413     {
01414         if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
01415             return;
01416         }
01417         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01418         if ( $this->_oTPrice !== null ) {
01419             return $this->_oTPrice;
01420         }
01421 
01422         $this->_oTPrice = oxNew( 'oxPrice' );
01423         $this->_oTPrice->setPrice( $this->oxarticles__oxtprice->value );
01424 
01425         $this->_applyVat( $this->_oTPrice, $this->getArticleVat() );
01426         $this->_applyCurrency( $this->_oTPrice );
01427 
01428         return $this->_oTPrice;
01429     }
01430 
01436     public function skipDiscounts()
01437     {
01438         // allready loaded skip discounts config
01439         if ( $this->_blSkipDiscounts !== null )
01440             return $this->_blSkipDiscounts;
01441 
01442         if ( $this->oxarticles__oxskipdiscounts->value )
01443             return true;
01444 
01445         $sO2CView = getViewName('oxobject2category');
01446         $sSelect =  "select 1 from $sO2CView as oxobject2category left join oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
01447         $sSelect .= 'where oxobject2category.oxobjectid="'.$this->getId().'" and oxcategories.oxactive'.(($this->getLanguage())?'_'.$this->getLanguage():'').' = 1 and oxcategories.oxskipdiscounts = "1" ';
01448 
01449         return $this->_blSkipDiscounts = ( oxDb::getDb()->getOne($sSelect) == 1 );
01450     }
01451 
01459     public function setPrice(oxPrice $oPrice)
01460     {
01461         $this->_oPrice = $oPrice;
01462     }
01463 
01472     public function getBasePrice( $dAmount = 1 )
01473     {
01474         // override this function if you want e.g. different prices
01475         // for diff. usergroups.
01476 
01477         // Performance
01478         $myConfig = $this->getConfig();
01479         if( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice )
01480             return;
01481 
01482         // GroupPrice or DB price ajusted by AmountPrice
01483         $dPrice = $this->_getAmountPrice( $dAmount );
01484 
01485 
01486         return $dPrice;
01487     }
01488 
01494     public function getPrice()
01495     {
01496         $myConfig = $this->getConfig();
01497         // Performance
01498         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
01499             return;
01500         }
01501         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01502         if ( $this->_oPrice ) {
01503             return $this->_oPrice;
01504         }
01505 
01506         $this->_oPrice = oxNew( 'oxPrice' );
01507 
01508         // get base
01509         $this->_oPrice->setPrice( $this->getBasePrice() );
01510 
01511         // price handling
01512         if ( !$this->_blCalcPrice ) {
01513             return $this->_oPrice;
01514         }
01515 
01516         $this->_calculatePrice( $this->_oPrice );
01517 
01518         return $this->_oPrice;
01519     }
01520 
01528     protected function _calculatePrice( $oPrice )
01529     {
01530         // apply VAT only if configuration requires it
01531         if ( !$this->getConfig()->getConfigParam( 'bl_perfCalcVatOnlyForBasketOrder' ) ) {
01532             $this->_applyVAT( $oPrice, $this->getArticleVat() );
01533         }
01534 
01535         // apply currency
01536         $this->_applyCurrency( $oPrice );
01537         // apply discounts
01538         if ( !$this->skipDiscounts() ) {
01539             $oDiscountList = oxDiscountList::getInstance();
01540             $oDiscountList->applyDiscounts( $oPrice, $oDiscountList->getArticleDiscounts($this, $this->getArticleUser() ) );
01541         }
01542 
01543         return $oPrice;
01544     }
01545 
01553     public function setArticleUser($oUser)
01554     {
01555         $this->_oUser = $oUser;
01556     }
01557 
01563     public function getArticleUser()
01564     {
01565         if ($this->_oUser) {
01566             return $this->_oUser;
01567         }
01568         return $this->getUser();
01569     }
01570 
01580     public function getBasketPrice( $dAmount, $aSelList, $oBasket )
01581     {
01582         $oUser = $oBasket->getBasketUser();
01583         $this->setArticleUser($oUser);
01584 
01585         $oBasketPrice = oxNew( 'oxPrice' );
01586 
01587         // get base price
01588         $dBasePrice = $this->getBasePrice( $dAmount );
01589 
01590         // applying select list price
01591         $this->_modifySelectListPrice( $dBasePrice, $aSelList );
01592 
01593         // setting price
01594         $oBasketPrice->setPrice( $dBasePrice );
01595 
01596         // apply VAT
01597         $this->_applyVat( $oBasketPrice, oxVatSelector::getInstance()->getBasketItemVat( $this, $oBasket ) );
01598 
01599         // apply currency
01600         $this->_applyCurrency( $oBasketPrice );
01601 
01602         // apply discounts
01603         if ( !$this->skipDiscounts() ) {
01604             // apply general discounts
01605             $oDiscountList = oxDiscountList::getInstance();
01606             $oDiscountList->applyDiscounts( $oBasketPrice, $oDiscountList->getArticleDiscounts( $this, $oUser ) );
01607         }
01608 
01609         // returning final price object
01610         return $oBasketPrice;
01611     }
01612 
01625     public function applyBasketDiscounts(oxPrice $oPrice, $aDiscounts, $dAmount = 1)
01626     {
01627         $oDiscountList = oxDiscountList::getInstance();
01628         return $oDiscountList->applyBasketDiscounts( $oPrice, $aDiscounts, $dAmount );
01629     }
01630 
01639     public function delete( $sOXID = null )
01640     {
01641         if ( !$sOXID ) {
01642             $sOXID = $this->getId();
01643         }
01644         if ( !$sOXID ) {
01645             return false;
01646         }
01647 
01648 
01649         $this->load( $sOXID );
01650         $this->_deletePics();
01651         $this->_onChangeResetCounts( $sOXID, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value );
01652         $this->_deleteVariantRecords( $sOXID );
01653         $rs = $this->_deleteRecords( $sOXID );
01654 
01655         oxSeoEncoderArticle::getInstance()->onDeleteArticle($this);
01656 
01657         $this->onChange( ACTION_DELETE, $sOXID, $this->oxarticles__oxparentid->value );
01658 
01659         return $rs->EOF;
01660     }
01661 
01670     public function updateSoldAmount( $iAmount = 0 )
01671     {
01672         if ( !$iAmount ) {
01673             return;
01674         }
01675 
01676         $this->beforeUpdate();
01677 
01678         // article is not variant - should be updated current amount
01679         if ( !$this->oxarticles__oxparentid->value ) {
01680             //updating by SQL query, due to wrong behaviour if saving article using not admin mode
01681             $rs = oxDb::getDb()->execute( "update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $iAmount, oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = '".$this->oxarticles__oxid->value."'");
01682         } elseif ( $this->oxarticles__oxparentid->value) {
01683             // article is variant - should be updated this article parent amount
01684             $oUpdateArticle = oxNewArticle( $this->oxarticles__oxparentid->value );
01685             $oUpdateArticle->updateSoldAmount( $iAmount );
01686         }
01687 
01688         $this->onChange( ACTION_UPDATE );
01689 
01690         return $rs;
01691     }
01692 
01698     public function disableReminder()
01699     {
01700         $oDB = oxDb::getDb(true);
01701         return $oDB->execute( "update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = '".$this->oxarticles__oxid->value."'");
01702     }
01703 
01710     public function save()
01711     {
01712         $myConfig = $this->getConfig();
01713 
01714         $this->oxarticles__oxthumb = new oxField(basename($this->oxarticles__oxthumb->value), oxField::T_RAW);
01715         $this->oxarticles__oxicon  = new oxField(basename($this->oxarticles__oxicon->value), oxField::T_RAW);
01716         $iPicCount = $myConfig->getConfigParam( 'iPicCount');
01717         for ($i=1; $i <= $iPicCount; $i++) {
01718             if ( isset($this->{'oxarticles__oxpic'.$i}) ) {
01719                 $this->{'oxarticles__oxpic'.$i}->setValue(basename($this->{'oxarticles__oxpic'.$i}->value));
01720             }
01721         }
01722         $iZoomPicCount = $myConfig->getConfigParam( 'iZoomPicCount' );
01723         for ($i=1; $i <= $iZoomPicCount; $i++) {
01724             if ( isset($this->{'oxarticles__oxzoom'.$i}) ) {
01725                 $this->{'oxarticles__oxzoom'.$i}->setValue(basename($this->{'oxarticles__oxzoom'.$i}->value));
01726             }
01727         }
01728 
01729         $blRet = parent::save();
01730 
01731         // save article long description
01732         $this->setArticleLongDesc();
01733         // load article images after save
01734         $this->_assignPictureValues();
01735 
01736         return $blRet;
01737     }
01738 
01739 
01746     public function getPictureGallery()
01747     {
01748         $myConfig = $this->getConfig();
01749 
01750         //initialize
01751         $blMorePic = false;
01752         $aArtPics  = array();
01753         $aArtIcons = array();
01754         $iActPicId = 1;
01755         $sActPic = $this->getPictureUrl( $iActPicId );
01756 
01757         if ( oxConfig::getParameter( 'actpicid' ) ) {
01758             $iActPicId = oxConfig::getParameter('actpicid');
01759         }
01760 
01761         $oStr = getStr();
01762         $iCntr = 0;
01763         $iPicCount = $myConfig->getConfigParam( 'iPicCount' );
01764         for ( $i = 1; $i <= $iPicCount; $i++) {
01765             $sPicVal = $this->getPictureUrl( $i );
01766             $sIcoVal = $this->getIconUrl( $i );
01767             if ( !$oStr->strstr($sIcoVal, 'nopic_ico.jpg')) {
01768                 if ($iCntr) {
01769                     $blMorePic = true;
01770                 }
01771                 $aArtIcons[$i]= $sIcoVal;
01772                 $aArtPics[$i]= $sPicVal;
01773                 $iCntr++;
01774             }
01775             if ($iActPicId == $i) {
01776                 $sActPic = $sPicVal;
01777             }
01778         }
01779 
01780         $blZoomPic  = false;
01781         $aZoomPics = array();
01782         $iZoomPicCount = $myConfig->getConfigParam( 'iZoomPicCount' );
01783         for ( $j = 1,$c = 1; $j <= $iZoomPicCount; $j++) {
01784             $sVal = $this->getZoomPictureUrl($j);
01785             if ( !$oStr->strstr($sVal, 'nopic.jpg')) {
01786                 if ($this->getConfig()->getConfigParam('blFormerTplSupport')) {
01787                     $sVal = $this->_sDynImageDir."/".$sVal;
01788                 }
01789                 $blZoomPic = true;
01790                 $aZoomPics[$c]['id'] = $c;
01791                 $aZoomPics[$c]['file'] = $sVal;
01792                 //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
01793                 if (!$sVal) {
01794                     $aZoomPics[$c]['file'] = "nopic.jpg";
01795                 }
01796                 $c++;
01797             }
01798         }
01799 
01800         $aPicGallery = array('ActPicID' => $iActPicId,
01801                              'ActPic' => $sActPic,
01802                              'MorePics' => $blMorePic,
01803                              'Pics' => $aArtPics,
01804                              'Icons' => $aArtIcons,
01805                              'ZoomPic' => $blZoomPic,
01806                              'ZoomPics' => $aZoomPics);
01807 
01808         return $aPicGallery;
01809     }
01810 
01824     public function onChange($sAction = null, $sOXID = null, $sParentID = null)
01825     {
01826         $myConfig = $this->getConfig();
01827 
01828         if (!isset($sOXID)) {
01829             if ( $this->getId()) {
01830                 $sOXID = $this->getId();
01831             }
01832             if (!isset ($sOXID)) {
01833                 $sOXID = $this->oxarticles__oxid->value;
01834             }
01835             if ($this->oxarticles__oxparentid->value) {
01836                 $sParentID = $this->oxarticles__oxparentid->value;
01837             }
01838         }
01839         if (!isset($sOXID)) {
01840             return;
01841         }
01842 
01843         //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
01844         if ( $myConfig->getConfigParam( 'blUseStock' ) ) {
01845             //if article has variants then updating oxvarstock field
01846             //getting parent id
01847             if (!isset($sParentID)) {
01848                 $sQ = 'select oxparentid from oxarticles where oxid = \''.$sOXID.'\'';
01849                 $sParentID = oxDb::getDb()->getOne($sQ);
01850             }
01851             //if we have parent id then update stock
01852             if ($sParentID) {
01853                 $this->_onChangeUpdateStock($sParentID);
01854             }
01855         }
01856         //if we have parent id then update count
01857         //update count even if blUseStock is not active
01858         if ($sParentID) {
01859             $this->_onChangeUpdateVarCount($sParentID);
01860         }
01861 
01862         $sId = ( $sParentID ) ? $sParentID : $sOXID;
01863         $this->_onChangeUpdateMinVarPrice( $sId );
01864 
01865     }
01866 
01873     public function getCustomVAT()
01874     {
01875         if ( isset($this->oxarticles__oxvat->value) ) {
01876             return $this->oxarticles__oxvat->value;
01877         }
01878     }
01879 
01887     public function checkForStock( $dAmount )
01888     {
01889         $myConfig = $this->getConfig();
01890         if ( !$myConfig->getConfigParam( 'blUseStock' ) ) {
01891             return true;
01892         }
01893 
01894         // fetching DB info as its up-to-date
01895         $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = "'.$this->getId().'" ';
01896         $rs = oxDb::getDb(true)->Execute( $sQ );
01897 
01898         $iOnStock   = 0;
01899         $iStockFlag = 0;
01900         if ( $rs !== false && $rs->recordCount() > 0 ) {
01901             $iOnStock   = $rs->fields['oxstock'];
01902             $iStockFlag = $rs->fields['oxstockflag'];
01903 
01904             // dodger : fremdlager is also always considered as on stock
01905             if ( $iStockFlag == 1 || $iStockFlag == 4) {
01906                 return true;
01907             }
01908             if ( !$myConfig->getConfigParam( 'blAllowUnevenAmounts' ) ) {
01909                 //2007-09-04 MK this if is NEVER true, because upper return in if $iStockFlag == 1 or $iStockFlag == 4
01910                 /* if ( $iStockFlag == 1 || $iStockFlag == 4 ) {
01911                     $iOnStock = ceil( $iOnStock );
01912                  } else {*/
01913                     $iOnStock = floor( $iOnStock );
01914                 //}
01915             }
01916         }
01917 
01918         if ( $iOnStock >= $dAmount ) {
01919             return true;
01920         } else {
01921             if ( $iOnStock > 0 ) {
01922                 return $iOnStock;
01923             } else {
01924                 return false;
01925             }
01926         }
01927     }
01928 
01929 
01937     public function getArticleLongDesc($sOXID = null)
01938     {
01939 
01940         if ( !$sOXID ) {
01941             $sOXID = $this->oxarticles__oxid->value;
01942         }
01943 
01944         if ($sOXID == $this->oxarticles__oxid->value) {
01945             if (isset($this->oxarticles__oxlongdesc) && ($this->oxarticles__oxlongdesc instanceof oxField) && $this->oxarticles__oxlongdesc->value) {
01946                 return $this->oxarticles__oxlongdesc;
01947             }
01948         }
01949 
01950         $myConfig = $this->getConfig();
01951 
01952         // TODO: check if keeping fldname is needed in non-admin mode
01953         $this->oxarticles__oxlongdesc = new oxField();
01954         $this->oxarticles__oxlongdesc->fldname = 'oxlongdesc';
01955         $this->oxarticles__oxlongdesc->table   = 'oxarticles';
01956         $this->oxarticles__oxlongdesc->fldtype = 'text';
01957 
01958         if ( $sOXID ) {
01959             $sLangField = oxLang::getInstance()->getLanguageTag($this->getLanguage());
01960             $this->oxarticles__oxlongdesc->setValue(oxDb::getDb()->getOne( "select oxlongdesc{$sLangField} from oxartextends where oxid = '$sOXID'" ), oxField::T_RAW);
01961 
01962             // TODO: eliminate code below
01963             // hack, if editor screws up text, htmledit tends to do so
01964             $this->oxarticles__oxlongdesc->setValue(str_replace( '&amp;nbsp;', '&nbsp;', $this->oxarticles__oxlongdesc->value ), oxField::T_RAW);
01965             $this->oxarticles__oxlongdesc->setValue(str_replace( '&amp;', '&', $this->oxarticles__oxlongdesc->value ), oxField::T_RAW);
01966             $this->oxarticles__oxlongdesc->setValue(str_replace( '&quot;', '"', $this->oxarticles__oxlongdesc->value ), oxField::T_RAW);
01967             $oStr = getStr();
01968             $blHasSmarty = $oStr->strstr( $this->oxarticles__oxlongdesc->value, '[{' );
01969             $blHasPhp = $oStr->strstr( $this->oxarticles__oxlongdesc->value, '<?' );
01970             if ( ( $blHasSmarty || $blHasPhp ) && ($myConfig->getConfigParam( 'blExport' ) || !$this->isAdmin() ) && $myConfig->getConfigParam( 'bl_perfParseLongDescinSmarty' ) ) {
01971                 $this->oxarticles__oxlongdesc->setValue(oxUtilsView::getInstance()->parseThroughSmarty( $this->oxarticles__oxlongdesc->value, $this->getId() ), oxField::T_RAW);
01972             }
01973         }
01974 
01975         return $this->oxarticles__oxlongdesc;
01976     }
01977 
01983     public function setArticleLongDesc()
01984     {
01985 
01986         if ( $this->_blEmployMultilanguage ) {
01987             // update or insert article long description
01988             if ($this->oxarticles__oxlongdesc instanceof oxField) {
01989                 $sLongDesc = $this->oxarticles__oxlongdesc->getRawValue();
01990             } else {
01991                 $sLongDesc = $this->oxarticles__oxlongdesc->value;
01992             }
01993             $this->_saveArtLongDesc($this->getLanguage(), $sLongDesc);
01994         } else {
01995             $oArtExt = oxNew('oxi18n');
01996             $oArtExt->init('oxartextends');
01997             $aObjFields = $oArtExt->_getAllFields(true);
01998             foreach ($aObjFields as $sKey => $sValue ) {
01999                 if ( preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey) ) {
02000                     $sField = $this->_getFieldLongName($sKey);
02001                     if (isset($this->$sField)) {
02002                         $iLang = $oArtExt->_getFieldLang($sKey);
02003                         $sLongDesc = null;
02004                         if ($this->$sField instanceof oxField) {
02005                             $sLongDesc = $this->$sField->getRawValue();
02006                         } elseif (is_object($this->$sField)) {
02007                             $sLongDesc = $this->$sField->value;
02008                         }
02009                         if (isset($sLongDesc)) {
02010                             $this->_saveArtLongDesc($iLang, $sLongDesc);
02011                         }
02012                     }
02013                 }
02014             }
02015         }
02016     }
02017 
02023     public function getAttributes()
02024     {
02025 
02026         if ($this->_oAttributeList) {
02027             return $this->_oAttributeList;
02028         }
02029 
02030         $oAttributeList = oxNew( 'oxattributelist' );
02031         $oAttributeList->loadAttributes( $this->getId());
02032         //if config option is set then the value for this object is also set
02033         //2007-02-09T
02034         $this->_oAttributeList = $oAttributeList;
02035 
02036         return $oAttributeList;
02037     }
02038 
02046     public function appendLink( $sAddParams )
02047     {
02048         if ( $this->_sDetailLink === null ) {
02049             $this->_sDetailLink = $this->getLink();
02050         }
02051         $this->_sDetailLink .= (( strpos( $this->_sDetailLink, '?' ) !== false ) ? '&amp;' : '?' ) . $sAddParams;
02052     }
02053 
02061     public function getLink($iLang = null)
02062     {
02063         if (isset($iLang)) {
02064             $iLang = (int) $iLang;
02065             if ($iLang == (int) $this->getLanguage()) {
02066                 $iLang = null;
02067             }
02068         }
02069         if ( $this->_sDetailLink === null || isset($iLang) ) {
02070 
02071             if ( oxUtils::getInstance()->seoIsActive() ) {
02072                 $oxdetaillink = oxSeoEncoderArticle::getInstance()->getArticleUrl( $this, $iLang, $this->_iLinkType);
02073             } else {
02074                 $oxdetaillink = $this->getStdLink($iLang);
02075             }
02076 
02077             if (isset($iLang)) {
02078                 return $oxdetaillink;
02079             } else {
02080                 $this->_sDetailLink = $oxdetaillink;
02081             }
02082         }
02083 
02084         return $this->_sDetailLink;
02085     }
02086 
02094     public function setLinkType( $iType )
02095     {
02096         // resetting detaisl link, to force new
02097         $this->_sDetailLink = null;
02098 
02099         // setting link type
02100         $this->_iLinkType = (int) $iType;
02101     }
02102 
02110     public function getStdLink($iLang = null)
02111     {
02112         //always returns shop url, not admin
02113         $this->_sStdLink  = $this->getConfig()->getShopHomeURL( $iLang, false );
02114         $this->_sStdLink .= "cl=details&amp;anid=".$this->getId();
02115 
02116         $blSeo = oxUtils::getInstance()->seoIsActive();
02117         if ( !$blSeo || $this->_iLinkType != 0 ) {
02118 
02119             if ( !$blSeo ) {
02120                 $iPgNr = (int) oxConfig::getParameter( 'pgNr' );
02121                 if ( $iPgNr > 0 ) {
02122                     $this->_sStdLink .= "&amp;pgNr={$iPgNr}";
02123                 }
02124             }
02125 
02126             if ( ( $sCat = oxConfig::getParameter( 'cnid' ) ) ) {
02127                 $this->_sStdLink .= "&amp;cnid={$sCat}";
02128             }
02129 
02130             if ( ( $sCat = oxConfig::getParameter( 'mnid' ) ) ) {
02131                 $this->_sStdLink .= "&amp;mnid={$sCat}";
02132             }
02133 
02134             $sListType = oxConfig::getParameter( 'listtype' );
02135             if ( !isset( $sListType ) ) {
02136                 // view defined list type
02137                 $sListType = $this->getConfig()->getGlobalParameter( 'listtype' );
02138             }
02139 
02140             // list type
02141             if ( $sListType ) {
02142                 $this->_sStdLink .= "&amp;listtype={$sListType}";
02143             }
02144 
02145             if (!$blSeo && isset($iLang)) {
02146                 $iLang = (int) $iLang;
02147                 if ($iLang != (int) $this->getLanguage()) {
02148                     $this->_sStdLink .= "&amp;lang={$iLang}";
02149                 }
02150             }
02151         }
02152 
02153         return $this->_sStdLink = $this->getSession()->processUrl( $this->_sStdLink );
02154     }
02155 
02163     public function getStdTagLink( $sTag )
02164     {
02165         $sStdTagLink = $this->getConfig()->getShopHomeURL( $this->getLanguage(), false );
02166         return $sStdTagLink . "cl=details&amp;anid=".$this->getId()."&amp;listtype=tag&amp;searchtag=".rawurlencode( $sTag );
02167     }
02168 
02174     public function getTags()
02175     {
02176         $sTagField = "oxtags".oxLang::getInstance()->getLanguageTag($this->getLanguage());
02177         $sQ = "select $sTagField from oxartextends where oxid = '".$this->getId()."'";
02178         $sTags = oxDb::getDb(true)->getOne($sQ);
02179         $oTagCloud = oxNew('oxtagcloud');
02180         $sTags = $oTagCloud->trimTags($sTags);
02181         return $sTags;
02182     }
02183 
02191     public function saveTags($sTags)
02192     {
02193         $sTags = mysql_real_escape_string($sTags);
02194         $oTagCloud = oxNew('oxtagcloud');
02195         $oTagCloud->resetTagCache();
02196         $sTags = $oTagCloud->prepareTags($sTags);
02197         $sTagField = "oxtags".oxLang::getInstance()->getLanguageTag($this->getLanguage());
02198         $sQ = "update oxartextends set $sTagField = '$sTags'  where oxid = '".$this->getId()."'";
02199         return oxDb::getDb()->execute($sQ);
02200 
02201     }
02202 
02210     public function addTag($sTag)
02211     {
02212         $sTag = mysql_real_escape_string($sTag);
02213 
02214         $oTagCloud = oxNew('oxtagcloud');
02215         $oTagCloud->resetTagCache();
02216         $sTag = $oTagCloud->prepareTags($sTag);
02217 
02218         $sField = "oxartextends.OXTAGS".oxLang::getInstance()->getLanguageTag();
02219         $sQ = "insert into oxartextends (oxartextends.OXID, $sField) values ('".$this->getId()."', '{$sTag}')
02220                        ON DUPLICATE KEY update $sField = CONCAT(TRIM($sField), ' $sTag') ";
02221 
02222         return oxDb::getDb()->Execute($sQ);
02223     }
02224 
02230     public function getMediaUrls()
02231     {
02232         if ($this->_aMediaUrls) {
02233             return $this->_aMediaUrls;
02234         }
02235 
02236         $this->_aMediaUrls = oxNew("oxlist");
02237         $this->_aMediaUrls->init("oxmediaurl");
02238         $this->_aMediaUrls->getBaseObject()->setLanguage( $this->getLanguage() );
02239 
02240         $sQ = "select * from oxmediaurls where oxobjectid = '".$this->getId()."'";
02241         $this->_aMediaUrls->selectString($sQ);
02242 
02243         return $this->_aMediaUrls;
02244     }
02245 
02251     public function getDynImageDir()
02252     {
02253         return $this->_sDynImageDir;
02254     }
02255 
02261     public function getDispSelList()
02262     {
02263         if ($this->_aDispSelList === null) {
02264             if ( $this->getConfig()->getConfigParam( 'bl_perfLoadSelectLists' ) && $this->getConfig()->getConfigParam( 'bl_perfLoadSelectListsInAList' ) ) {
02265                 $this->_aDispSelList = $this->getSelectLists();
02266             }
02267         }
02268         return $this->_aDispSelList;
02269     }
02270 
02276     public function getMoreDetailLink()
02277     {
02278         if ( $this->_sMoreDetailLink == null ) {
02279 
02280             // and assign special article values
02281             $this->_sMoreDetailLink = $this->getConfig()->getShopHomeURL() . 'cl=moredetails';
02282 
02283             // not always it is okey, as not all the time active category is the same as primary article cat.
02284             if ( $sActCat = oxConfig::getParameter( 'cnid' ) ) {
02285                 $this->_sMoreDetailLink .= '&amp;cnid='.$sActCat;
02286             }
02287             $this->_sMoreDetailLink .= '&amp;anid='.$this->getId();
02288             $this->_sMoreDetailLink = $this->getSession()->processUrl( $this->_sMoreDetailLink );
02289         }
02290 
02291         return $this->_sMoreDetailLink;
02292     }
02293 
02299     public function getToBasketLink()
02300     {
02301         if ( $this->_sToBasketLink == null ) {
02302             $myConfig = $this->getConfig();
02303 
02304             if ( oxUtils::getInstance()->isSearchEngine() ) {
02305                 $this->_sToBasketLink = $this->getLink();
02306             } else {
02307                 // and assign special article values
02308                 $this->_sToBasketLink = $myConfig->getShopHomeURL();
02309 
02310                 // override some classes as these should never showup
02311                 $sActClass = oxConfig::getParameter( 'cl' );
02312                 if ( $sActClass == 'thankyou') {
02313                     $sActClass = 'basket';
02314                 }
02315                 $this->_sToBasketLink .= 'cl='.$sActClass;
02316 
02317                 // this is not very correct
02318                 if ( $sActCat = oxConfig::getParameter( 'cnid' ) ) {
02319                     $this->_sToBasketLink .= '&amp;cnid='.$sActCat;
02320                 }
02321 
02322                 $this->_sToBasketLink .= '&amp;fnc=tobasket&amp;aid='.$this->getId().'&amp;anid='.$this->getId();
02323 
02324                 if ( $sTpl = basename( oxConfig::getParameter( 'tpl' ) ) ) {
02325                     $this->_sToBasketLink .= '&amp;tpl='.$sTpl;
02326                 }
02327             }
02328 
02329             $this->_sToBasketLink = $this->getSession()->processUrl( $this->_sToBasketLink );
02330         }
02331 
02332         return $this->_sToBasketLink;
02333     }
02334 
02340     public function getStockStatus()
02341     {
02342         return $this->_iStockStatus;
02343     }
02344 
02350     public function getDeliveryDate()
02351     {
02352         if ( $this->oxarticles__oxdelivery->value != '0000-00-00') {
02353             return oxUtilsDate::getInstance()->formatDBDate( $this->oxarticles__oxdelivery->value);
02354         } else {
02355             return false;
02356         }
02357     }
02358 
02364     public function getFTPrice()
02365     {
02366         if ( $oPrice = $this->getTPrice() ) {
02367             if ( $oPrice->getBruttoPrice() ) {
02368                 return oxLang::getInstance()->formatCurrency( oxUtils::getInstance()->fRound($oPrice->getBruttoPrice()));
02369             }
02370         } else {
02371             return null;
02372         }
02373     }
02374 
02380     public function getFPrice()
02381     {
02382         if ( $oPrice = $this->getPrice() ) {
02383             return $this->getPriceFromPrefix().oxLang::getInstance()->formatCurrency( $oPrice->getBruttoPrice() );
02384         } else {
02385             return null;
02386         }
02387     }
02388 
02394     public function getPricePerUnit()
02395     {
02396         return $this->_fPricePerUnit;
02397     }
02398 
02404     public function isParentNotBuyable()
02405     {
02406         return $this->_blNotBuyableParent;
02407     }
02408 
02414     public function isNotBuyable()
02415     {
02416         return $this->_blNotBuyable;
02417     }
02418 
02426     public function setBuyableState( $blBuyable = false )
02427     {
02428         $this->_blNotBuyable = !$blBuyable;
02429     }
02430 
02436     public function getVariantList()
02437     {
02438         return $this->_oVariantList;
02439     }
02440 
02448     public function setSelectlist( $aSelList )
02449     {
02450         $this->_aDispSelList = $aSelList;
02451     }
02452 
02460     public function getPictureUrl( $iIndex )
02461     {
02462         return $this->getConfig()->getPictureUrl( $this->{"oxarticles__oxpic".$iIndex}->value );
02463     }
02464 
02472     public function getIconUrl( $iIndex = '')
02473     {
02474         if (!$iIndex) {
02475             $sFile = $this->oxarticles__oxicon->value;
02476         } else {
02477             $sFile = $this->{'oxarticles__oxpic' . $iIndex . '_ico'}->value;
02478         }
02479 
02480         $sFile = str_replace('nopic.jpg', 'nopic_ico.jpg', $sFile);
02481 
02482         //$sFile = $this->getConfig()->getPictureUrl( 'icon/' ). basename($sFile);
02483         $sFile = $this->getConfig()->getPictureUrl( $sFile );
02484 
02485         return $sFile;
02486     }
02487 
02493     public function getThumbnailUrl()
02494     {
02495         //return $this->getConfig()->getPictureUrl( $this->oxarticles__oxthumb->value );
02496         return $this->getConfig()->getPictureUrl( '0/' ) . basename($this->oxarticles__oxthumb->value);
02497     }
02498 
02506     public function getZoomPictureUrl($iIndex)
02507     {
02508         return $this->getConfig()->getPictureUrl( $this->{'oxarticles__oxzoom'.$iIndex}->value );
02509     }
02510 
02516     public function getFileUrl()
02517     {
02518         return $this->getConfig()->getPictureUrl( '0/' );
02519     }
02520 
02526     public function getPriceFromPrefix()
02527     {
02528         $sPricePrefics = '';
02529         if ( $this->_blIsRangePrice) {
02530             $sPricePrefics = oxLang::getInstance()->translateString('priceFrom').' ';
02531         }
02532 
02533         return $sPricePrefics;
02534     }
02535 
02544     protected function _saveArtLongDesc($iLang, $sValue)
02545     {
02546         $oDB = oxDb::getDb();
02547         $iLang = (int) $iLang;
02548         $sLangField = ($iLang > '0') ? '_'.$iLang : '';
02549         $sLongDesc = $oDB->quote($sValue);
02550         $sLongDescSQL = "insert into oxartextends (oxartextends.OXID, oxartextends.OXLONGDESC{$sLangField})
02551                        VALUES ('".$this->getId()."', {$sLongDesc})
02552                        ON DUPLICATE KEY update oxartextends.OXLONGDESC{$sLangField} = {$sLongDesc} ";
02553 
02554         $oDB->execute($sLongDescSQL);
02555     }
02556 
02572     protected function _removeInactiveVariants( $oVariants, $blStrict = false )
02573     {
02574         $myConfig = $this->getConfig();
02575         $this->_iVarStock = 0;
02576         $this->_blHasVariants = false;
02577         $now = time();
02578         $sSearchdate = date('Y-m-d H:i:s', $now);
02579         $this->_iVarStock = $this->oxarticles__oxvarstock->value;
02580 
02581         //checking if variant is active and stock status
02582         foreach (array_keys($oVariants->getArray()) as $key ) {
02583 
02584             $oVariant = $oVariants[$key];
02585             $this->_blHasVariants = true;
02586             //removing variants not in stock
02587             if ( $myConfig->getConfigParam( 'blUseStock' ) &&
02588                 $oVariant->oxarticles__oxstockflag->value != 1 && $oVariant->oxarticles__oxstockflag->value != 4 &&
02589                 ($oVariant->oxarticles__oxstockflag->value != 3 || $blStrict) && $oVariant->oxarticles__oxstock->value <= 0) {
02590                     unset($oVariants[$key]);
02591                     continue;
02592             }
02593 
02594             //removing non active variants
02595             if (!$oVariant->oxarticles__oxactive->value &&
02596                 !($oVariant->oxarticles__oxactivefrom->value < $sSearchdate &&
02597                 $oVariant->oxarticles__oxactiveto->value > $sSearchdate) ) {
02598                     unset($oVariants[$key]);
02599                     continue;
02600             }
02601         }
02602 
02603         //if we have variants then depending on config option the parent may be non buyable
02604         if (!$myConfig->getConfigParam( 'blVariantParentBuyable' ) && $this->_blHasVariants ) {
02605             $this->_blNotBuyableParent = true;
02606         }
02607 
02608         //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
02609         if (!$myConfig->getConfigParam( 'blVariantParentBuyable' ) && $oVariants->count() == 0 && $this->_blHasVariants) {
02610             $this->_blNotBuyable = true;
02611         }
02612 
02613         return $oVariants;
02614     }
02615 
02622     protected function _skipSaveFields()
02623     {
02624         $myConfig = $this->getConfig();
02625 
02626         $this->_aSkipSaveFields = array();
02627 
02628         $this->_aSkipSaveFields[] = 'oxtimestamp';
02629         $this->_aSkipSaveFields[] = 'oxlongdesc';
02630         $this->_aSkipSaveFields[] = 'oxinsert';
02631 
02632         if ( !isset( $this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '') {
02633             $this->_aSkipSaveFields[] = 'oxparentid';
02634         }
02635 
02636     }
02637 
02647     protected function _mergeDiscounts( $aDiscounts, $aItemDiscounts)
02648     {
02649         foreach ( $aItemDiscounts as $sKey => $oDiscount ) {
02650             // add prices of the same discounts
02651             if ( array_key_exists ($sKey, $aDiscounts) ) {
02652                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
02653             } else {
02654                 $aDiscounts[$sKey] = $oDiscount;
02655             }
02656         }
02657         return $aDiscounts;
02658     }
02659 
02665     protected function _getGroupPrice()
02666     {
02667         $dPrice = $this->oxarticles__oxprice->value;
02668 
02669         $oUser = $this->getArticleUser();
02670         if ( $oUser ) {
02671             if ( $oUser->inGroup( 'oxidpricea' ) ) {
02672                 $dPrice = $this->oxarticles__oxpricea->value;
02673             } elseif ( $oUser->inGroup( 'oxidpriceb' ) ) {
02674                 $dPrice = $this->oxarticles__oxpriceb->value;
02675             } elseif ( $oUser->inGroup( 'oxidpricec' ) ) {
02676                 $dPrice = $this->oxarticles__oxpricec->value;
02677             }
02678         }
02679 
02680         // #1437/1436C - added config option, and check for zero A,B,C price values
02681         if ( $this->getConfig()->getConfigParam( 'blOverrideZeroABCPrices' ) && (double) $dPrice == 0 ) {
02682             $dPrice = $this->oxarticles__oxprice->value;
02683         }
02684 
02685         return $dPrice;
02686     }
02687 
02696     protected function _getAmountPrice($dAmount = 1)
02697     {
02698         $myConfig = $this->getConfig();
02699 
02700         startProfile( "_getAmountPrice" );
02701 
02702         $dPrice = $this->_getGroupPrice();
02703         $oAmtPrices = $this->_getAmountPriceList();
02704         foreach ($oAmtPrices as $oAmPrice) {
02705             if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
02706                     && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
02707                     && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value ) {
02708                 $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
02709             }
02710         }
02711 
02712         stopProfile( "_getAmountPrice" );
02713         return $dPrice;
02714     }
02715 
02724     protected function _modifySelectListPrice( &$dPrice, $aChosenList = null )
02725     {
02726         $myConfig = $this->getConfig();
02727         // #690
02728         if ( $myConfig->getConfigParam( 'bl_perfLoadSelectLists' ) && $myConfig->getConfigParam( 'bl_perfUseSelectlistPrice' ) ) {
02729 
02730             $aSelLists = $this->getSelectLists();
02731             foreach ( $aSelLists as $key => $aSel) {
02732                 if ( isset( $aChosenList[$key]) && isset($aSel[$aChosenList[$key]] ) ) {
02733                     $oSel = $aSel[$aChosenList[$key]];
02734                     if ( $oSel->priceUnit =='abs' ) {
02735                         $dPrice += $oSel->price;
02736                     } elseif ( $oSel->priceUnit =='%' ) {
02737                         $dPrice += oxPrice::percent( $dPrice, $oSel->price );
02738                     }
02739                 }
02740             }
02741         }
02742         return $dPrice;
02743     }
02744 
02745 
02753     protected function _fillAmountPriceList($oAmPriceList)
02754     {
02755         $myConfig = $this->getConfig();
02756         $myUtils  = oxUtils::getInstance();
02757 
02758         //modifying price
02759         $oCur = $myConfig->getActShopCurrencyObject();
02760 
02761         $oUser = $this->getArticleUser();
02762 
02763         $oDiscountList = oxDiscountList::getInstance();
02764         $aDiscountList = $oDiscountList->getArticleDiscounts( $this, $oUser );
02765 
02766         $oLowestPrice = null;
02767 
02768         $dBasePrice = $this->_getGroupPrice();
02769         $oLang = oxLang::getInstance();
02770 
02771         $dArticleVat = null;
02772         if ( !$myConfig->getConfigParam( 'bl_perfCalcVatOnlyForBasketOrder' ) ) {
02773             $dArticleVat = $this->getArticleVat();
02774         }
02775 
02776         // trying to find lowest price value
02777         foreach ($oAmPriceList as $sId => $oItem) {
02778             $oItemPrice = oxNew( 'oxprice' );
02779             if ( $oItem->oxprice2article__oxaddabs->value) {
02780                 $oItemPrice->setPrice( $oItem->oxprice2article__oxaddabs->value );
02781                 $oDiscountList->applyDiscounts( $oItemPrice, $aDiscountList );
02782                 $this->_applyCurrency( $oItemPrice, $oCur );
02783             } else {
02784                 $oItemPrice->setPrice( $dBasePrice );
02785                 $oItemPrice->subtractPercent( $oItem->oxprice2article__oxaddperc->value );
02786             }
02787 
02788             if (isset($dArticleVat)) {
02789                 $this->_applyVAT($oItemPrice, $dArticleVat);
02790             }
02791 
02792             if (!$oLowestPrice) {
02793                 $oLowestPrice = $oItemPrice;
02794             } elseif ($oLowestPrice->getBruttoPrice() > $oItemPrice->getBruttoPrice()) {
02795                 $oLowestPrice = $oItemPrice;
02796             }
02797 
02798             $oAmPriceList[$sId]->oxprice2article__oxaddabs = new oxField( $oLang->formatCurrency( $myUtils->fRound( $oItemPrice->getBruttoPrice(), $oCur ) ) );
02799             $oAmPriceList[$sId]->fnetprice  = $oLang->formatCurrency( $myUtils->fRound($oItemPrice->getNettoPrice(), $oCur ) );
02800             $oAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency( $myUtils->fRound($oItemPrice->getBruttoPrice(), $oCur ) );
02801         }
02802 
02803         $this->_dAmountPrice = $myUtils->fRound( $oLowestPrice->getBruttoPrice() );
02804         return $oAmPriceList;
02805     }
02806 
02812     protected function _getVariantsIds()
02813     {
02814         $aSelect = array();
02815         $oRs = oxDb::getDb(true)->execute( "select oxid from oxarticles where oxparentid = '".$this->oxarticles__oxid->value."' " );
02816         if ( $oRs != false && $oRs->recordCount() > 0 ) {
02817             while (!$oRs->EOF) {
02818                 $aSelect[] = $oRs->fields['oxid'];
02819                 $oRs->moveNext();
02820             }
02821         }
02822         return $aSelect;
02823     }
02824 
02830     public function getArticleVat()
02831     {
02832         if (!isset($this->_dArticleVat)) {
02833             $this->_dArticleVat = oxVatSelector::getInstance()->getArticleVat( $this );
02834         }
02835         return $this->_dArticleVat;
02836     }
02837 
02846     protected function _applyVAT( oxPrice $oPrice, $dVat )
02847     {
02848         startProfile(__FUNCTION__);
02849         $oPrice->setVAT( $dVat );
02850         if ( ($dVat = oxVatSelector::getInstance()->getArticleUserVat($this)) !== false ) {
02851             $oPrice->setUserVat( $dVat );
02852         }
02853         stopProfile(__FUNCTION__);
02854     }
02855 
02863     public function applyVats( oxPrice $oPrice )
02864     {
02865         $this->_applyVAT($oPrice,
02866                          $this->getArticleVat()
02867                         );
02868     }
02869 
02880     protected function _applyDiscounts( $oPrice, $aDiscounts )
02881     {
02882         $oDiscountList = oxDiscountList::getInstance();
02883         $oDiscountList->applyDiscounts( $oPrice, $aDiscounts );
02884     }
02885 
02893     public function applyDiscountsForVariant( $oPrice )
02894     {
02895         // apply discounts
02896         if ( !$this->skipDiscounts() ) {
02897             $oDiscountList = oxDiscountList::getInstance();
02898             $oDiscountList->applyDiscounts( $oPrice, $oDiscountList->getArticleDiscounts( $this, $this->getArticleUser() ) );
02899         }
02900     }
02901 
02910     protected function _applyCurrency(oxPrice $oPrice, $oCur = null )
02911     {
02912         if ( !$oCur ) {
02913             $oCur = $this->getConfig()->getActShopCurrencyObject();
02914         }
02915 
02916         $oPrice->multiply($oCur->rate);
02917     }
02918 
02927     protected function _getIcon()
02928     {
02929         // #1479/1179M - Article icon automatic generation
02930         //if set to do not generate.
02931         $myConfig = $this->getConfig();
02932 
02933         if (!$myConfig->getConfigParam( 'blAutoIcons' ) ) {
02934             if ($this->oxarticles__oxicon->value) {
02935                 return basename($this->oxarticles__oxicon->value);
02936             } else {
02937                 $sQ = "UPDATE oxarticles SET oxicon = 'nopic_ico.jpg' WHERE oxid = '".$this->getId()."'";
02938                 oxDb::getDb()->execute($sQ);
02939                 return 'nopic_ico.jpg';
02940             }
02941         }
02942 
02943         // if set to generate and icon already exist
02944         if ( $this->oxarticles__oxicon->value && strpos( $this->oxarticles__oxicon->value, 'nopic_ico.jpg') === false ) {
02945             return basename($this->oxarticles__oxicon->value);
02946         }
02947 
02948         //we don't have an icon yet so lets make one
02949         if ($this->oxarticles__oxthumb->value && strpos( $this->oxarticles__oxthumb->value, 'nopic.jpg') === false &&  function_exists('gd_info')) {
02950 
02951             $sSourceFile = $this->oxarticles__oxthumb->value;
02952             $sTargetFile = str_replace('_th', '_ico', $sSourceFile);
02953 
02954             if ($sSourceFile == $sTargetFile) {
02955                 $sPattern = '/(\.[a-z0-9]*$)/i';
02956                 $sTargetFile = preg_replace($sPattern, '_ico\\1', $sTargetFile);
02957             }
02958 
02959             $sTarget = $myConfig->getAbsDynImageDir().'/icon/'. basename($sTargetFile);
02960             $sSource = $myConfig->getAbsDynImageDir().'/0/'. basename($sSourceFile);
02961 
02962             if (!$myConfig->getConfigParam( 'sIconsize' ) ) {
02963                 $myConfig->setConfigParam( 'sIconsize', '56*42' );
02964             }
02965 
02966             $aSize = explode('*', $myConfig->getConfigParam( 'sIconsize' ) );
02967             $iX = $aSize[0];
02968             $iY = $aSize[1];
02969 
02970             oxUtilspic::getInstance()->resizeImage( $sSource, $sTarget, $iX, $iY );
02971 
02972             $sResult = $sTargetFile;
02973         } else {
02974             $sResult = 'nopic_ico.jpg';
02975         }
02976 
02977         //saving new icon
02978         $sIconFile = basename($sResult);
02979 
02980         $sQ = "UPDATE oxarticles SET oxicon = '$sIconFile' WHERE oxid = '".$this->getId()."'";
02981 
02982         oxDb::getDb()->execute($sQ);
02983 
02984         return $sIconFile;
02985     }
02986 
02987 
02996     protected function _getAttribsString(&$sAttribs, &$iCnt)
02997     {
02998         // we do not use lists here as we dont need this overhead right now
02999         $oDB = oxDb::getDb(true);
03000         $sSelect =  'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid="'.$this->oxarticles__oxid->value.'" ';
03001         $sAttribs = '';
03002         $blSep = false;
03003         $rs = $oDB->execute( $sSelect);
03004         $iCnt = 0;
03005         if ($rs != false && $rs->recordCount() > 0) {
03006             while (!$rs->EOF) {
03007                 if ( $blSep) {
03008                     $sAttribs .= ' or ';
03009                 }
03010                 $sAttribs .= 't1.oxattrid = "'.$rs->fields['oxattrid'].'" ';
03011                 $blSep = true;
03012                 $iCnt++;
03013                 $rs->moveNext();
03014             }
03015         }
03016     }
03017 
03026     protected function _getSimList($sAttribs, $iCnt)
03027     {
03028         $myConfig = $this->getConfig();
03029         $oDB      = oxDb::getDb(true);
03030 
03031         // #523A
03032         $iAttrPercent = $myConfig->getConfigParam( 'iAttributesPercent' )/100;
03033         // 70% same attributes
03034         if ( !$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
03035             $iAttrPercent = 0.70;
03036         }
03037         // #1137V iAttributesPercent = 100 doesnt work
03038         $iHitMin = ceil( $iCnt * $iAttrPercent );
03039 
03040         // we do not use lists here as we dont need this overhead right now
03041         $aList= array();
03042         $sSelect =  "select oxobjectid, count(*) as cnt from oxobject2attribute as t1 where
03043                     ( $sAttribs )
03044                     and t1.oxobjectid != '".$this->oxarticles__oxid->value."'
03045                     group by t1.oxobjectid having count(*) >= $iHitMin ";
03046 
03047         $rs = $oDB->selectLimit( $sSelect, 20, 0);
03048         if ($rs != false && $rs->recordCount() > 0) {
03049             while (!$rs->EOF) {
03050                 $oTemp = new stdClass();    // #663
03051                 $oTemp->cnt = $rs->fields['cnt'];
03052                 $oTemp->id  = $rs->fields['oxobjectid'];
03053                 $aList[] = $oTemp;
03054                 $rs->moveNext();
03055             }
03056         }
03057         return $aList;
03058     }
03059 
03068     protected function _generateSimListSearchStr($sArticleTable, $aList)
03069     {
03070         $myConfig = $this->getConfig();
03071         $sFieldList = $this->getSelectFields();
03072         $sSearch = "select $sFieldList from $sArticleTable where ".$this->getSqlActiveSnippet()."  and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
03073         $blSep = false;
03074         $iCnt = 0;
03075         foreach ( $aList as $oTemp) {
03076             if ( $blSep) {
03077                 $sSearch .= ',';
03078             }
03079             $sSearch .= "'".$oTemp->id."'";
03080             $blSep = true;
03081             if ( $iCnt >= $myConfig->getConfigParam( 'iNrofSimilarArticles' ) ) {
03082                 break;
03083             }
03084             $iCnt++;
03085         }
03086 
03087         //#1741T
03088         //$sSearch .= ") and $sArticleTable.oxparentid = '' ";
03089         $sSearch .= ') ';
03090 
03091         // #524A -- randomizing articles in attribute list
03092         $sSearch .= ' order by rand() ';
03093 
03094         return $sSearch;
03095     }
03096 
03105     protected function _generateSearchStr($sOXID, $blSearchPriceCat = false )
03106     {
03107         $sCatView = getViewName( 'oxcategories' );
03108         $sO2CView = getViewName( 'oxobject2category' );
03109 
03110         // we do not use lists here as we dont need this overhead right now
03111         if ( !$blSearchPriceCat ) {
03112             $sSelect  = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
03113                          {$sCatView}.oxid = oxobject2category.oxcatnid
03114                          where oxobject2category.oxobjectid='{$sOXID}' and {$sCatView}.oxid is not null ";
03115         } else {
03116             $sSelect  = "select {$sCatView}.* from {$sCatView} where
03117                          '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
03118                          '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
03119         }
03120         return $sSelect;
03121     }
03122 
03128     protected function _generateSearchStrForCustomerBought()
03129     {
03130         $sArtTable = $this->_getObjectViewName( 'oxarticles' );
03131         $sOrderArtTable = getViewName( 'oxorderarticles' );
03132 
03133         // fetching filter params
03134         $sIn = " '{$this->oxarticles__oxid->value}' ";
03135         if ( $this->oxarticles__oxparentid->value ) {
03136 
03137             // adding article parent
03138             $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
03139             $sParentIdForVariants = $this->oxarticles__oxparentid->value;
03140 
03141         } else {
03142             $sParentIdForVariants = $this->getId();
03143         }
03144 
03145         // adding variants
03146         $oRs = oxDb::getDb(true)->execute( "select oxid from {$sArtTable} where oxparentid = '{$sParentIdForVariants}' and oxid != '{$this->oxarticles__oxid->value}' " );
03147         if ( $oRs != false && $oRs->recordCount() > 0) {
03148             while ( !$oRs->EOF ) {
03149                 $sIn .= ", '".current( $oRs->fields )."' ";
03150                 $oRs->moveNext();
03151             }
03152         }
03153 
03154         $iLimit = (int) $this->getConfig()->getConfigParam( 'iNrofCustomerWhoArticles' );
03155         $iLimit = $iLimit?( $iLimit * 10 ): 50;
03156 
03157         // building sql (optimized)
03158         $sQ = "select distinct {$sArtTable}.* from (
03159                    select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
03160                ) as suborder
03161                left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
03162                left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
03163                where {$sArtTable}.oxid not in ( {$sIn} )
03164                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and ".$this->getSqlActiveSnippet();
03165 
03166         /* non optimized, but could be used if index forcing is not supported
03167         // building sql
03168         $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
03169                    select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
03170                ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
03171                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
03172                and ".$this->getSqlActiveSnippet();
03173         */
03174 
03175         return $sQ;
03176     }
03177 
03187     protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
03188     {
03189         $sCategoryView = getViewName('oxcategories');
03190         $sO2CView = getViewName('oxobject2category');
03191         $sLangPrefix = (($this->getLanguage())?'_'.$this->getLanguage():'');
03192         if (!$dPriceFromTo) {
03193             $sSelect  = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
03194             $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
03195             $sSelect .= "where oxobject2category.oxcatnid='$sCatId' and oxobject2category.oxobjectid='$sOXID' ";
03196             $sSelect .= "and oxcategories.oxactive$sLangPrefix = 1 order by oxobject2category.oxtime ";
03197         } else {
03198             $sSelect  = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
03199             $sSelect .= "oxcategories.oxid='$sCatId' and '$dPriceFromTo' >= oxcategories.oxpricefrom and ";
03200             $sSelect .= "'$dPriceFromTo' <= oxcategories.oxpriceto ";
03201         }
03202         return $sSelect;
03203     }
03204 
03210     protected function _getAmountPriceList()
03211     {
03212         if ($this->_oAmountPriceList) {
03213             return $this->_oAmountPriceList;
03214         }
03215 
03216         $myConfig = $this->getConfig();
03217 
03218         $sArtID  = $this->getId();
03219 
03220         // #1690C - Scale prices and variants
03221         if ( !$this->isAdmin() && $myConfig->getConfigParam( 'blVariantInheritAmountPrice' ) && $this->oxarticles__oxparentid->value ) {
03222             $sArtID = $this->oxarticles__oxparentid->value;
03223         }
03224 
03225         // echo( "TODO replace oxlist usage here _collectAmPriceList".PHP_EOL);
03226         $sArtID = mysql_real_escape_string($sArtID);
03227 
03228         //collecting assigned to article amount-price list
03229         $oAmPriceList = oxNew( 'oxlist');
03230         $oAmPriceList->init('oxbase', 'oxprice2article');
03231 
03232         $sShopID = $myConfig->getShopID();
03233         if ( $myConfig->getConfigParam( 'blMallInterchangeArticles' ) ) {
03234             $sShopSelect = '1';
03235         } else {
03236             $sShopSelect = " oxshopid =  '$sShopID' ";
03237         }
03238 
03239         $oAmPriceList->selectString( "select * from oxprice2article where oxartid = '$sArtID' and $sShopSelect order by oxamount ");
03240 
03241         // prepare abs prices if currently having percentages
03242         $oBasePrice = $this->_getGroupPrice();
03243         foreach ($oAmPriceList as $oAmPrice) {
03244             if ($oAmPrice->oxprice2article__oxaddperc->value) {
03245                 $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent( $oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value ), oxField::T_RAW);
03246             }
03247         }
03248 
03249         $this->_oAmountPriceList = $oAmPriceList;
03250         return $oAmPriceList;
03251     }
03252 
03260     protected function _isFieldEmpty($sFieldName)
03261     {
03262         $mValue = $this->$sFieldName->value;
03263 
03264         if (is_null($mValue)) {
03265             return true;
03266         }
03267 
03268         if ($mValue === '') {
03269             return true;
03270         }
03271 
03272         $aDoubleCopyFields = array('oxarticles__oxprice',
03273                                        'oxarticles__oxvat');
03274 
03275         if (!$mValue && in_array($sFieldName, $aDoubleCopyFields)) {
03276             return true;
03277         }
03278 
03279 
03280         if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
03281             return true;
03282         }
03283 
03284         $sFieldName = strtolower($sFieldName);
03285 
03286         if ($mValue == "nopic_ico.jpg" && $sFieldName == 'oxarticles__oxicon') {
03287             return true;
03288         }
03289 
03290         if ($mValue == "nopic.jpg" && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom')) {
03291             return true;
03292         }
03293 
03294         return false;
03295     }
03296 
03304     protected function _assignParentFieldValue($sFieldName)
03305     {
03306         if (!($oParentArticle = $this->_getParentAricle())) {
03307             return;
03308         }
03309 
03310         $sCopyFieldName = $this->_getFieldLongName($sFieldName);
03311 
03312         // assigning only theese which parent article has
03313         if ( $oParentArticle->$sCopyFieldName != null ) {
03314 
03315             // only overwrite database values
03316             if ( substr( $sCopyFieldName, 0, 12) != 'oxarticles__') {
03317                 continue;
03318             }
03319 
03320             //do not copy certain fields
03321             $aNonCopyFields = array('oxarticles__oxinsert',
03322                                     'oxarticles__oxtimestamp',
03323                                     'oxarticles__oxnid',
03324                                     'oxarticles__oxid',
03325                                     'oxarticles__oxparentid');
03326 
03327             $aCopyParentField = array('oxarticles__oxnonmaterial',
03328                                       'oxarticles__oxfreeshipping',
03329                                       'oxarticles__oxremindactive');
03330 
03331             if (in_array($sCopyFieldName, $aNonCopyFields)) {
03332                 return;
03333             }
03334 
03335 
03336 
03337             //do not copy parent data for icons in case we have (need) own variant icon (in case variant thumbnail exists)
03338             if ($sFieldName == "oxicon" && !$this->_isFieldEmpty("oxarticles__oxthumb") && $this->oxarticles__oxthumb->value != $oParentArticle->oxarticles__oxthumb->value && $this->getConfig()->getConfigParam( 'blAutoIcons' ) ) {
03339                 return ;
03340             }
03341 
03342             //COPY THE VALUE
03343             //replaced the code bellow with this two liner
03344             //T2009-01-12
03345             if ($this->_isFieldEmpty($sCopyFieldName) || in_array($sCopyFieldName, $aCopyParentField)) {
03346                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03347             }
03348 
03349 
03350             /*
03351             //#1101S empty image fields (without nopic.jpg, nopic_ico.jpg) should be copied from parent too
03352             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 == '')) {
03353                 // pictures
03354                 if ( $this->_blLoadParentData && $this->isAdmin() ) {
03355                     $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03356                 } else {
03357                     $aFile = explode( '/', $oParentArticle->$sCopyFieldName->value);
03358                     $this->$sCopyFieldName->setValue(basename);
03359                 }
03360             } elseif ( $this->$sCopyFieldName->value == '' ||
03361                     $this->$sCopyFieldName->value == '0000-00-00 00:00:00' ||
03362                     $this->$sCopyFieldName->value == '0000-00-00' ||
03363                     ( in_array($sCopyFieldName, $aDoubleCopyFields) && $this->$sCopyFieldName->value == 0)
03364                    ) {
03365                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03366             }
03367 
03368             //another fields which should be copied from parent if empty and not covered by above condition
03369             $aCopyParentField = array('oxarticles__oxnonmaterial',
03370                                       'oxarticles__oxfreeshipping',
03371                                       'oxarticles__oxremindactive');
03372             if (!$this->$sCopyFieldName->value && in_array($sCopyFieldName, $aCopyParentField)) {
03373                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
03374             }*/
03375         }
03376     }
03377 
03383     protected function _getParentAricle()
03384     {
03385         $sParentId = $this->oxarticles__oxparentid->value;
03386         if (!$sParentId) {
03387             return null;
03388         }
03389         if (isset(self::$_aLoadedParents[$sParentId])) {
03390             return self::$_aLoadedParents[$sParentId];
03391         } else {
03392             $oParentArticle = oxNew( 'oxarticle' );
03393             $oParentArticle->_blSkipAbPrice = true;
03394             $oParentArticle->_blLoadPrice = false;
03395             $oParentArticle->_blLoadVariants = false;
03396             $oParentArticle->load( $sParentId);
03397             self::$_aLoadedParents[$sParentId] = $oParentArticle;
03398             return $oParentArticle;
03399         }
03400     }
03401 
03407     protected function _assignParentFieldValues()
03408     {   startProfile('articleAssignParentInternal');
03409         if ( $this->oxarticles__oxparentid->value) {
03410             // yes, we are in fact a variant
03411             if ( !$this->isAdmin() || ($this->_blLoadParentData && $this->isAdmin() ) ) {
03412                 foreach ($this->_aFieldNames as $sFieldName => $sVal) {
03413                     $this->_assignParentFieldValue($sFieldName);
03414                 }
03415 
03416                 //assing long description
03417                 $oParentArticle = $this->_getParentAricle();
03418                 if ( !$this->oxarticles__oxlongdesc->value ) {
03419                     $this->oxarticles__oxlongdesc = $oParentArticle->oxarticles__oxlongdesc;
03420                 }
03421             }
03422         } elseif ( $this->oxarticles__oxid->value ) {
03423             // I am not a variant but I might have some
03424             //$this->_oVariantList = $this->getSimpleVariants();
03425             startProfile("loadVariants");
03426             $this->_oVariantList = $this->getVariants();
03427             stopProfile("loadVariants");
03428             // #1650M - article title with <br> tag
03429             // htmlspecialchars parses only 5 characters, so i have stiped out '<' and '>'
03430             /*
03431             if ( !$this->isAdmin() ) {
03432                 $this->oxarticles__oxtitle->setValue(str_replace(array('&', "'", '"'), array('&amp;', '&#039;', '&quot;'), $this->oxarticles__oxtitle->value));
03433             }*/
03434         }
03435         stopProfile('articleAssignParentInternal');
03436 
03437     }
03438 
03444     protected function _assignNotBuyableParent()
03445     {
03446         if ( !$this->getConfig()->getConfigParam( 'blVariantParentBuyable' ) &&
03447              ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value )) {
03448             $this->_blNotBuyableParent = true;
03449 
03450         }
03451     }
03452 
03458     protected function _assignPictureValues()
03459     {
03460         $myConfig = $this->getConfig();
03461         $this->oxarticles__oxicon = new oxField($this->_getIcon());
03462 
03463         // picture isset($this->_aFieldNames["thumb"]) && re handling
03464         $sNoPic     = 'nopic.jpg';
03465         $sNoPicIcon = 'nopic_ico.jpg';
03466 
03467         if ( isset($this->_aFieldNames["oxthumb"]) && !$this->oxarticles__oxthumb->value) {
03468             $this->oxarticles__oxthumb = new oxField($sNoPic);
03469         }
03470         /*
03471         if( isset($this->_aFieldNames["oxicon"]) && !isset($this->oxarticles__oxicon->value))
03472             $this->oxarticles__oxicon  = new oxField($sNoPicIcon);
03473         */
03474 
03475         $iPicCount = $myConfig->getConfigParam( 'iPicCount' );
03476         for ( $i=1; $i<= $iPicCount; $i++ ) {
03477             if ( isset($this->_aFieldNames["oxpic".$i]) &&  !$this->{'oxarticles__oxpic'.$i}->value ) {
03478                 $this->{'oxarticles__oxpic'.$i} = new oxField($sNoPic);
03479             }
03480         }
03481 
03482         $iZoomPicCount = $myConfig->getConfigParam( 'iZoomPicCount' );
03483         for ( $i=1; $i<= $iZoomPicCount; $i++ ) {
03484             if ( isset($this->_aFieldNames["oxzoom".$i]) &&  !$this->{'oxarticles__oxzoom'.$i}->value) {
03485                 $this->{'oxarticles__oxzoom'.$i} = new oxField($sNoPic);
03486             }
03487         }
03488 
03489         if ( !$this->isAdmin() ) {
03490             // add directories
03491             if ( isset($this->_aFieldNames["oxthumb"])) {
03492                 $this->oxarticles__oxthumb->setValue('0/'.basename($this->oxarticles__oxthumb->value));
03493             }
03494             if ( isset($this->_aFieldNames["oxicon"])) {
03495                 $this->oxarticles__oxicon = new oxField('icon/'.basename($this->oxarticles__oxicon->value));
03496             }
03497 
03498             $myUtilsPic = oxUtilsPic::getInstance();
03499             for ( $i=1; $i<= $iPicCount; $i++ ) {
03500                 $sFieldName = 'oxarticles__oxpic'.$i;
03501                 if ( isset($this->_aFieldNames["oxpic".$i])) {
03502                     $sIconFieldName = 'oxarticles__oxpic'.$i.'_ico';
03503                     $this->$sIconFieldName = new oxField($i.'/'.basename($myUtilsPic->iconName($this->$sFieldName->value)));
03504                     $this->$sFieldName     = new oxField($i.'/'.basename($this->$sFieldName->value));
03505                 }
03506             }
03507             for ( $i=1; $i<= $iZoomPicCount; $i++ ) {
03508                 if ( isset($this->_aFieldNames["oxzoom".$i])) {
03509                     $this->{'oxarticles__oxzoom'.$i} = new oxField('z'.$i.'/'.basename($this->{'oxarticles__oxzoom'.$i}->value));
03510                 }
03511             }
03512         }
03513 
03514     }
03515 
03521     protected function _assignStock()
03522     {
03523         $myConfig = $this->getConfig();
03524         // -----------------------------------
03525         // stock
03526         // -----------------------------------
03527 
03528         // #1125 A. must round (using floor()) value taken from database and cast to int
03529         if (!$myConfig->getConfigParam( 'blAllowUnevenAmounts' ) && !$this->isAdmin() ) {
03530             $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
03531         }
03532         //GREEN light
03533         $this->_iStockStatus = 0;
03534 
03535         // if we have flag /*1 or*/ 4 - we show always green light
03536         if ( $myConfig->getConfigParam( 'blUseStock' ) && /*$this->oxarticles__oxstockflag->value != 1 && */ $this->oxarticles__oxstockflag->value != 4) {
03537             //ORANGE light
03538             $iStock = $this->oxarticles__oxstock->value;
03539 
03540             if ($this->_blNotBuyableParent) {
03541                 $iStock = $this->oxarticles__oxvarstock->value;
03542             }
03543 
03544 
03545             if ( $iStock <= $myConfig->getConfigParam( 'sStockWarningLimit' ) && $iStock > 0) {
03546                 $this->_iStockStatus = 1;
03547             }
03548 
03549             //RED light
03550             if ($iStock <= 0) {
03551                 $this->_iStockStatus = -1;
03552             }
03553         }
03554 
03555 
03556         // stock
03557         if ( $myConfig->getConfigParam( 'blUseStock' ) && $this->oxarticles__oxstock->value <= 0 && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
03558             $this->_blNotBuyable = true;
03559         }
03560 
03561         //exceptional handling for variant parent stock:
03562         if ($this->_blNotBuyable && $this->_iVarStock) {
03563             $this->_blNotBuyable = false;
03564             //but then at least setting notBuaybleParent to true
03565             $this->_blNotBuyableParent = true;
03566         }
03567 
03568         //special treatment for lists when blVariantParentBuyable config option is set to false
03569         //then we just hide "to basket" button.
03570         //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
03571         if ( !$myConfig->getConfigParam( 'blVariantParentBuyable' ) && !$myConfig->getConfigParam( 'blLoadVariants' ) && $this->oxarticles__oxvarstock->value) {
03572             $this->_blNotBuyable = true;
03573         }
03574 
03575         //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
03576         if ($this->_blNotBuyableParent && count($this->_oVariantList) == 0) {
03577             $this->_blNotBuyable = true;
03578         }
03579     }
03580 
03586     protected function _assignPrices()
03587     {
03588         $myConfig = $this->getConfig();
03589 
03590         // Performance
03591         if ( !$myConfig->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
03592             return;
03593         }
03594 
03595 
03596         // compute price
03597         $dPrice = $this->getPrice()->getBruttoPrice();
03598 
03599         $oCur = $myConfig->getActShopCurrencyObject();
03600         //price per unit handling
03601         if ((double) $this->oxarticles__oxunitquantity->value && $this->oxarticles__oxunitname->value) {
03602             $this->_fPricePerUnit = oxLang::getInstance()->formatCurrency($dPrice / (double) $this->oxarticles__oxunitquantity->value, $oCur);
03603         }
03604 
03605 
03606         //getting min and max prices of variants
03607         $this->_applyRangePrice();
03608     }
03609 
03615     protected function _assignPersistentParam()
03616     {
03617         // Persistent Parameter Handling
03618         $aPersParam     = oxSession::getVar( 'persparam');
03619         if ( isset( $aPersParam) && isset( $aPersParam[$this->getId()])) {
03620             $this->_aPersistParam = $aPersParam[$this->getId()];
03621         }
03622     }
03623 
03629     protected function _assignDynImageDir()
03630     {
03631         $myConfig = $this->getConfig();
03632 
03633         $sThisShop = $this->oxarticles__oxshopid->value;
03634 
03635         $this->_sDynImageDir   = $myConfig->getPictureUrl( null, false );
03636         $this->dabsimagedir    = $myConfig->getPictureDir( false ); //$sThisShop
03637         $this->nossl_dimagedir = $myConfig->getPictureUrl( null, false, false, null, $sThisShop ); //$sThisShop
03638         $this->ssl_dimagedir   = $myConfig->getPictureUrl( null, false, true, null, $sThisShop ); //$sThisShop
03639     }
03640 
03646     protected function _assignComparisonListFlag()
03647     {
03648         // #657 add a flag if article is on comparisonlist
03649 
03650         $aItems = oxConfig::getParameter('aFiltcompproducts');
03651         if ( isset( $aItems[$this->getId()])) {
03652             $this->_blIsOnComparisonList = true;
03653         }
03654     }
03655 
03661     protected function _assignAttributes()
03662     {
03663         //#1029T load attributes
03664         //#1078S removed check for module "Produktvergleich"
03665         if ( $this->getConfig()->getConfigParam( 'bl_perfLoadAttributes' ) ) {
03666             $this->getAttributes();
03667         }
03668     }
03669 
03670 
03678     protected function _insert()
03679     {
03680         // set oxinsert
03681         $iInsertTime = time();
03682         $now = date('Y-m-d H:i:s', $iInsertTime);
03683         $this->oxarticles__oxinsert    = new oxField( $now );
03684         $this->oxarticles__oxtimestamp = new oxField( $now );
03685         if ( !is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
03686             $this->oxarticles__oxsubclass = new oxField('oxarticle');
03687         }
03688 
03689         return parent::_insert();
03690     }
03691 
03697     protected function _update()
03698     {
03699 
03700         $myConfig = $this->getConfig();
03701 
03702 
03703         $this->_skipSaveFields();
03704 
03705         return parent::_update();
03706     }
03707 
03715     protected function _deleteRecords($sOXID)
03716     {
03717 
03718         //delete the record
03719         $oDB = oxDb::getDb();
03720         $sDelete = 'delete from '.$this->_sCoreTbl.' where oxid = \''.$sOXID.'\' ';
03721         $oDB->execute( $sDelete);
03722 
03723         //remove other records
03724         $sDelete = 'delete from oxobject2article where oxarticlenid = \''.$sOXID.'\' or oxobjectid = \''.$sOXID.'\' ';
03725         $oDB->execute( $sDelete);
03726 
03727         $sDelete = 'delete from oxobject2attribute where oxobjectid = \''.$sOXID.'\' ';
03728         $oDB->execute( $sDelete);
03729 
03730         $sDelete = 'delete from oxobject2category where oxobjectid = \''.$sOXID.'\' ';
03731         $oDB->execute( $sDelete);
03732 
03733         $sDelete = 'delete from oxobject2selectlist where oxobjectid = \''.$sOXID.'\' ';
03734         $oDB->execute( $sDelete);
03735 
03736         $sDelete = 'delete from oxprice2article where oxartid = \''.$sOXID.'\' ';
03737         $oDB->execute( $sDelete);
03738 
03739         $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = \''.$sOXID.'\' ';
03740         $oDB->execute( $sDelete);
03741 
03742         $sDelete = 'delete from oxaccessoire2article where oxobjectid = "'.$sOXID.'" or oxarticlenid = "'.$sOXID.'" ';
03743         $oDB->execute( $sDelete);
03744 
03745         //#1508C - deleting oxobject2delivery entries added
03746         $sDelete = 'delete from oxobject2delivery where oxobjectid = \''.$sOXID.'\' and oxtype=\'oxarticles\' ';
03747         $oDB->execute( $sDelete);
03748 
03749         $sDelete = 'delete from oxartextends where oxid = \''.$sOXID.'\' ';
03750         $oDB->execute( $sDelete);
03751 
03752         $sDelete = 'delete from oxactions2article where oxartid = \''.$sOXID.'\' ';
03753         $rs = $oDB->execute( $sDelete );
03754 
03755 
03756         return $rs;
03757     }
03758 
03766     protected function _deleteVariantRecords($sOXID)
03767     {
03768         $oDB = oxDb::getDb();
03769         //collect variants to remove recursively
03770         $sVariants = 'select oxid from '.$this->getViewName().' where oxparentid = \''.$sOXID.'\'';
03771         $rs = $oDB->execute( $sVariants);
03772         if ($rs != false && $rs->recordCount() > 0) {
03773             while (!$rs->EOF) {
03774                 $this->delete( $rs->fields[0]);
03775                 $rs->moveNext();
03776             }
03777         }
03778     }
03779 
03789     protected function _resetCacheAndArticleCount( $sOxid )
03790     {
03791         $this->_onChangeResetCounts( $sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value );
03792     }
03793 
03799     protected function _deletePics()
03800     {
03801         $myUtilsPic = oxUtilsPic::getInstance();
03802         $myConfig   = $this->getConfig();
03803 
03804         // #1173M - not all pic are deleted, after article is removed
03805         $blThumbDeleted = $myUtilsPic->safePictureDelete( $this->oxarticles__oxthumb->value, $myConfig->getAbsDynImageDir().'/0', 'oxarticles', 'oxthumb' );
03806 
03807         if ( $blThumbDeleted ) {
03808             $myUtilsPic->safePictureDelete('icon/'.$this->oxarticles__oxicon->value, $myConfig->getAbsDynImageDir(), 'oxarticles', 'oxicon' );
03809         }
03810         //removed and replaced with savePcitureDelete MAFI
03811         //if( $blThumbDeleted && $myUtilsPic->isPicDeletable( $this->oxarticles__oxthumb->value, 'oxarticles', 'oxicon' )) {
03812             //TODO: is it correct that oxarticles__oxthumb is checked and oxarticles__oxicon deleted? if not replace this with safePictureDelete MAFI
03813          //   $myUtilsPic->deletePicture( 'icon/'.$this->oxarticles__oxicon->value, $myConfig->getAbsDynImageDir(), '' $myConfig->getConfigParam( 'blIsOXDemoShop' ));
03814         //}
03815 
03816         $iPicCount = $myConfig->getConfigParam( 'iPicCount' );
03817         $sAbsDynImageDir = $myConfig->getAbsDynImageDir();
03818         for ( $i = 1; $i <= $iPicCount; $i++ ) {
03819             // Getting coresponding pic's filename value
03820             $sPicFName = $this->{'oxarticles__oxpic'.$i}->value;
03821             $myUtilsPic->safePictureDelete($sPicFName, $sAbsDynImageDir.'/'.$i, 'oxarticles', 'oxpic'.$i );
03822         }
03823         // deleting zoom images
03824         $iZoomPicCount = $myConfig->getConfigParam( 'iZoomPicCount' );
03825         for ( $i = 1; $i <= $iZoomPicCount; $i++ ) {
03826             if ( isset($this->{'oxarticles__oxzoom'.$i}) ) {
03827                 $myUtilsPic->safePictureDelete($this->{'oxarticles__oxzoom'.$i}->value, $sAbsDynImageDir.'/z'.$i, 'oxarticles', 'oxzoom'.$i );
03828             }
03829         }
03830 
03831     }
03832 
03842     protected function _onChangeResetCounts( $sOxid, $sVendorId = null, $sManufacturerId = null )
03843     {
03844 
03845         $myUtilsCount = oxUtilsCount::getInstance();
03846 
03847         if ( $sVendorId ) {
03848             $myUtilsCount->resetVendorArticleCount( $sVendorId );
03849         }
03850 
03851         if ( $sManufacturerId ) {
03852             $myUtilsCount->resetManufacturerArticleCount( $sManufacturerId );
03853         }
03854 
03855         //also reseting category counts
03856         $sQ = "select oxcatnid from oxobject2category where oxobjectid = '{$sOxid}'";
03857         $oRs = oxDb::getDb()->execute( $sQ );
03858         if ( $oRs !== false && $oRs->recordCount() > 0) {
03859             while ( !$oRs->EOF ) {
03860                 $myUtilsCount->resetCatArticleCount( $oRs->fields[0] );
03861                 $oRs->moveNext();
03862             }
03863         }
03864     }
03865 
03873     protected function _onChangeUpdateStock( $sParentID )
03874     {
03875         $oDb = oxDb::getDb();
03876         $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = \''.$sParentID.'\' ';
03877         $rs = $oDb->execute($sQ);
03878         $iOldStock = $rs->fields[0];
03879         $iVendorID = $rs->fields[1];
03880         $iManufacturerID = $rs->fields[2];
03881 
03882         $sQ = 'select sum(oxstock) from oxarticles where oxparentid = \''.$sParentID.'\' and '. $this->getSqlActiveSnippet( true ).' and oxstock > 0 ';
03883         $iStock = (float) $oDb->getOne( $sQ );
03884 
03885         $sQ = 'update oxarticles set oxvarstock = '.$iStock.' where oxid = \''.$sParentID.'\'';
03886         $oDb->execute( $sQ );
03887 
03888             //now lets update category counts
03889             //first detect stock status change for this article (to or from 0)
03890             if ( $iStock < 0 ) {
03891                 $iStock = 0;
03892             }
03893             if ( $iOldStock < 0 ) {
03894                 $iOldStock = 0;
03895             }
03896             if ( $this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock ) {
03897                 //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
03898                 // so far we leave it like this but later we could move all count resets to one or two functions
03899                 $this->_onChangeResetCounts( $sParentID, $iVendorID, $iManufacturerID );
03900             }
03901     }
03902 
03910     protected function _onChangeUpdateVarCount( $sParentID )
03911     {
03912         $oDb = oxDb::getDb();
03913         $sQ = 'select count(*) as varcount from oxarticles where oxparentid = \''.$sParentID.'\' ';
03914         $iVarCount = (int) $oDb->getOne($sQ);
03915 
03916         $sQ = 'update oxarticles set oxvarcount = '.$iVarCount.' where oxid = \''.$sParentID.'\'';
03917         $oDb->execute($sQ);
03918     }
03919 
03927     protected function _onChangeUpdateMinVarPrice( $sParentID )
03928     {
03929         //#M0000883 (Sarunas)
03930         $sQ = 'select min(oxprice) as varminprice from oxarticles where '.$this->getSqlActiveSnippet(true).' and (oxparentid = "'.$sParentID.'"';
03931         //#M0000886 (Sarunas)
03932         if ( $this->getConfig()->getConfigParam( 'blVariantParentBuyable' ) ) {
03933             $sQ .= ' or oxid = "'.$sParentID.'"';
03934         } else {
03935             $sQ .= ' or (oxid = "'.$sParentID.'" and oxvarcount=0)';
03936         }
03937         $sQ .= ')';
03938         $oDb = oxDb::getDb();
03939         $dVarMinPrice = $oDb->getOne($sQ);
03940         if ( $dVarMinPrice ) {
03941             $sQ = 'update oxarticles set oxvarminprice = '.$dVarMinPrice.' where oxid = "'.$sParentID.'"';
03942             $oDb->execute($sQ);
03943         }
03944     }
03945 
03946 
03952     protected function _applyRangePrice()
03953     {
03954         //#buglist_413 if bl_perfLoadPriceForAddList variant price shouldn't be loaded too
03955         if ( !$this->getConfig()->getConfigParam( 'bl_perfLoadPrice' ) || !$this->_blLoadPrice ) {
03956             return;
03957         }
03958 
03959         $this->_blIsRangePrice = false;
03960 
03961         // if parent is buyable - do not apply range price calcculations
03962         if ($this->_blSkipAbPrice || !$this->_blNotBuyableParent) {
03963             return;
03964         }
03965 
03966         $aPrices = array();
03967 
03968         if (!$this->_blNotBuyableParent) {
03969             $aPrices[] = $this->getPrice()->getBruttoPrice();
03970         }
03971 
03972         if (count($this->_oVariantList)) {
03973             foreach ($this->_oVariantList as $sKey => $oVariant) {
03974                 $aPrices[] = $oVariant->getPrice()->getBruttoPrice();
03975             }
03976         }
03977 
03978         /*  $oAmPrices = $this->loadAmountPriceInfo();
03979         foreach ($oAmPrices as $oAmPrice) {
03980             $aPrices[] = $oAmPrice->oxprice2article__oxaddabs->value;
03981         }*/
03982 
03983         if (count($aPrices)) {
03984             $dMinPrice = $aPrices[0];
03985             $dMaxPrice = $aPrices[0];
03986             foreach ($aPrices as $dPrice) {
03987                 if ($dMinPrice > $dPrice) {
03988                     $dMinPrice = $dPrice;
03989                 }
03990 
03991                 if ($dMaxPrice < $dPrice) {
03992                     $dMaxPrice = $dPrice;
03993                 }
03994             }
03995         }
03996 
03997         if ($this->_blNotBuyableParent && isset($dMinPrice) && $dMinPrice == $dMaxPrice) {
03998             $this->getPrice()->setBruttoPriceMode();
03999             $this->getPrice()->setPrice($dMinPrice);
04000         }
04001 
04002         if (isset($dMinPrice) && $dMinPrice != $dMaxPrice) {
04003             $this->getPrice()->setBruttoPriceMode();
04004             $this->getPrice()->setPrice($dMinPrice);
04005             $this->_blIsRangePrice = true;
04006         }
04007 
04008         if ( $this->isParentNotBuyable() && !$this->getConfig()->getConfigParam( 'blLoadVariants' )) {
04009             $this->getPrice()->setBruttoPriceMode();
04010             $this->getPrice()->setPrice($this->oxarticles__oxvarminprice->value);
04011             $this->_blIsRangePrice = true;
04012             $this->_calculatePrice( $this->getPrice() );
04013         }
04014     }
04015 
04021     public function getProductId()
04022     {
04023         return $this->getId();
04024     }
04025 
04031     public function getProductParentId()
04032     {
04033         return $this->oxarticles__oxparentid->value;
04034     }
04035 
04041     public function isOrderArticle()
04042     {
04043         return false;
04044     }
04045 
04051     public function isVariant()
04052     {
04053         return (bool) ( isset( $this->oxarticles__oxparentid ) ? $this->oxarticles__oxparentid->value : false );
04054     }
04055 }

Generated on Tue Aug 18 09:21:05 2009 for OXID eShop CE by  doxygen 1.5.5