oxarticle.php

Go to the documentation of this file.
00001 <?php
00002 
00003 // defining supported link types
00004 define('OXARTICLE_LINKTYPE_CATEGORY', 0);
00005 define('OXARTICLE_LINKTYPE_VENDOR', 1);
00006 define('OXARTICLE_LINKTYPE_MANUFACTURER', 2);
00007 define('OXARTICLE_LINKTYPE_PRICECATEGORY', 3);
00008 define('OXARTICLE_LINKTYPE_TAG', 4);
00009 define('OXARTICLE_LINKTYPE_RECOMM', 5);
00010 
00017 class oxArticle extends oxI18n implements oxIArticle, oxIUrl
00018 {
00019 
00020 
00026     protected $_sClassName = 'oxarticle';
00027 
00033     protected $_blUseLazyLoading = true;
00034 
00040     protected $_sItemKey;
00041 
00048     protected $_blCalcPrice = true;
00049 
00055     protected $_oPrice = null;
00056 
00057 
00063     protected $_dVarMinPrice = null;
00064 
00070     protected $_dVarMaxPrice = null;
00071 
00077     protected $_dArticleVat = null;
00078 
00084     protected $_aPersistParam = null;
00085 
00091     protected $_blNotBuyable = false;
00092 
00099     protected $_blLoadVariants = true;
00100 
00106     protected $_aVariants = null;
00107 
00113     protected $_aVariantsWithNotOrderables = null;
00114 
00123     protected $_blNotBuyableParent = false;
00124 
00125 
00129     protected $_blHasVariants = false;
00130 
00134     protected $_blHasMdVariants = false;
00135 
00141     protected $_blIsOnComparisonList = false;
00142 
00148     protected $_oUser = null;
00149 
00156     protected $_blLoadPrice = true;
00157 
00164     protected $_fPricePerUnit = null;
00165 
00169     protected $_blLoadParentData = false;
00170 
00174     protected $_blAllowEmptyParentId = false;
00175 
00179     protected $_blSkipAssign = false;
00180 
00186     protected $_blSkipDiscounts = null;
00187 
00192     protected $_oAttributeList = null;
00193 
00194 
00200     protected $_blIsRangePrice = null;
00201 
00207     protected $_aMediaUrls = null;
00208 
00214     static protected $_aLoadedParents;
00215 
00221     static protected $_aSelList;
00222 
00228     protected $_aDispSelList;
00229 
00235     protected $_blIsSeoObject = true;
00236 
00242     protected $_oAmountPriceList = null;
00243 
00252     protected $_iLinkType = 0;
00253 
00259     protected $_aStdUrls = array();
00260 
00266     protected $_aSeoUrls = array();
00267 
00273     protected $_aSeoAddParams = array();
00274 
00280     protected $_aStdAddParams = array();
00281 
00287     protected $_sDynImageDir = null;
00288 
00294     protected $_sMoreDetailLink = null;
00295 
00301     protected $_sToBasketLink = null;
00302 
00308     protected $_iStockStatusOnLoad = null;
00309 
00315     protected $_aSortingFieldsOnLoad = array();
00316 
00322     protected $_iStockStatus = null;
00323 
00329     protected $_oTPrice = null;
00330 
00336     protected $_oAmountPriceInfo = null;
00337 
00343     protected $_dAmountPrice = null;
00344 
00350     protected static $_aArticleManufacturers = array();
00351 
00357     protected static $_aArticleVendors = array();
00358 
00364     protected static $_aArticleCats = array();
00365 
00371     protected $_aNonCopyParentFields = array('oxarticles__oxinsert',
00372                                              'oxarticles__oxtimestamp',
00373                                              'oxarticles__oxnid',
00374                                              'oxarticles__oxid',
00375                                              'oxarticles__oxparentid');
00376 
00382     protected $_aCopyParentField = array('oxarticles__oxnonmaterial',
00383                                          'oxarticles__oxfreeshipping',
00384                                          'oxarticles__oxisdownloadable',
00385                                          'oxarticles__oxshowcustomagreement');
00386 
00392     protected $_oMdVariants = null;
00393 
00399     protected $_oLongDesc = null;
00400 
00408     protected $_aVariantSelections = array();
00409 
00415     protected static $_aSelections = array();
00416 
00422     protected static $_aCategoryCache = null;
00423 
00429     protected static $_blHasAmountPrice = null;
00430 
00436     protected $_aArticleFiles = null;
00437 
00443     protected $_blCanUpdateAnyField = null;
00444 
00453     public function __construct($aParams = null)
00454     {
00455         if ($aParams && is_array($aParams)) {
00456             foreach ($aParams as $sParam => $mValue) {
00457                 $this->$sParam = $mValue;
00458             }
00459         }
00460         parent::__construct();
00461         $this->init('oxarticles');
00462     }
00463 
00472     public function __get($sName)
00473     {
00474         $this->$sName = parent::__get($sName);
00475         if ($this->$sName) {
00476             // since the field could have been loaded via lazy loading
00477             $this->_assignParentFieldValue($sName);
00478         }
00479 
00480         return $this->$sName;
00481     }
00482 
00489     public function __set($sName, $sValue)
00490     {
00491         parent::__set($sName, $sValue);
00492     }
00493 
00500     public function isInList()
00501     {
00502         return $this->_isInList();
00503     }
00504 
00512     public function setId($sId = null)
00513     {
00514         $sId = parent::setId($sId);
00515 
00516         // TODO: in oxbase::setId make it to check if exists and update, not recreate, then delete this overload
00517         $this->oxarticles__oxnid = $this->oxarticles__oxid;
00518 
00519         return $sId;
00520     }
00521 
00531     public function getActiveCheckQuery($blForceCoreTable = null)
00532     {
00533         $sTable = $this->getViewName($blForceCoreTable);
00534 
00535         // check if article is still active
00536         $sQ = " $sTable.oxactive = 1 ";
00537 
00538         // enabled time range check ?
00539         if ($this->getConfig()->getConfigParam('blUseTimeCheck')) {
00540             $sDate = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
00541             $sQ = "( $sQ or ( $sTable.oxactivefrom < '$sDate' and $sTable.oxactiveto > '$sDate' ) ) ";
00542         }
00543 
00544         return $sQ;
00545     }
00546 
00560     public function getStockCheckQuery($blForceCoreTable = null)
00561     {
00562         $myConfig = $this->getConfig();
00563         $sTable = $this->getViewName($blForceCoreTable);
00564 
00565         $sQ = "";
00566 
00567         //do not check for variants
00568         if ($myConfig->getConfigParam('blUseStock')) {
00569             $sQ = " and ( $sTable.oxstockflag != 2 or ( $sTable.oxstock + $sTable.oxvarstock ) > 0  ) ";
00570             //V #M513: When Parent article is not purchasable, it's visibility should be displayed in shop only if any of Variants is available.
00571             if (!$myConfig->getConfigParam('blVariantParentBuyable')) {
00572                 $sTimeCheckQ = '';
00573                 if ($myConfig->getConfigParam('blUseTimeCheck')) {
00574                     $sDate = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
00575                     $sTimeCheckQ = " or ( art.oxactivefrom < '$sDate' and art.oxactiveto > '$sDate' )";
00576                 }
00577                 $sQ = " $sQ and IF( $sTable.oxvarcount = 0, 1, ( select 1 from $sTable as art where art.oxparentid=$sTable.oxid and ( art.oxactive = 1 $sTimeCheckQ ) and ( art.oxstockflag != 2 or art.oxstock > 0 ) limit 1 ) ) ";
00578             }
00579         }
00580 
00581         return $sQ;
00582     }
00583 
00595     public function getVariantsQuery($blRemoveNotOrderables, $blForceCoreTable = null)
00596     {
00597         $sTable = $this->getViewName($blForceCoreTable);
00598         $sQ = " and $sTable.oxparentid = '" . $this->getId() . "' ";
00599 
00600         //checking if variant is active and stock status
00601         if ($this->getConfig()->getConfigParam('blUseStock')) {
00602             $sQ .= " and ( $sTable.oxstock > 0 or ( $sTable.oxstock <= 0 and $sTable.oxstockflag != 2 ";
00603             if ($blRemoveNotOrderables) {
00604                 $sQ .= " and $sTable.oxstockflag != 3 ";
00605             }
00606             $sQ .= " ) ) ";
00607         }
00608 
00609         return $sQ;
00610     }
00611 
00617     public function getUnitQuantity()
00618     {
00619         return $this->oxarticles__oxunitquantity->value;
00620     }
00621 
00627     public function getSize()
00628     {
00629         $dSize = $this->oxarticles__oxlength->value *
00630                  $this->oxarticles__oxwidth->value *
00631                  $this->oxarticles__oxheight->value;
00632 
00633         return $dSize;
00634     }
00635 
00641     public function getWeight()
00642     {
00643         return $this->oxarticles__oxweight->value;
00644     }
00645 
00653     public function getSqlActiveSnippet($blForceCoreTable = null)
00654     {
00655         // check if article is still active
00656         $sQ = $this->getActiveCheckQuery($blForceCoreTable);
00657 
00658         // stock and variants check
00659         $sQ .= $this->getStockCheckQuery($blForceCoreTable);
00660 
00661 
00662         return "( $sQ ) ";
00663     }
00664 
00670     public function setSkipAssign($blSkipAssign)
00671     {
00672         $this->_blSkipAssign = $blSkipAssign;
00673     }
00674 
00678     public function disablePriceLoad()
00679     {
00680         $this->_blLoadPrice = false;
00681     }
00682 
00686     public function enablePriceLoad()
00687     {
00688         $this->_blLoadPrice = true;
00689     }
00690 
00696     public function getItemKey()
00697     {
00698         return $this->_sItemKey;
00699     }
00700 
00706     public function setItemKey($sItemKey)
00707     {
00708         $this->_sItemKey = $sItemKey;
00709     }
00710 
00716     public function setNoVariantLoading($blLoadVariants)
00717     {
00718         $this->_blLoadVariants = !$blLoadVariants;
00719     }
00720 
00726     public function isBuyable()
00727     {
00728         if ($this->_blNotBuyableParent) {
00729             return false;
00730         }
00731 
00732         return !$this->_blNotBuyable;
00733     }
00734 
00740     public function getPersParams()
00741     {
00742         return $this->_aPersistParam;
00743     }
00744 
00750     public function isOnComparisonList()
00751     {
00752         return $this->_blIsOnComparisonList;
00753     }
00754 
00760     public function setOnComparisonList($blOnList)
00761     {
00762         $this->_blIsOnComparisonList = $blOnList;
00763     }
00764 
00770     public function setLoadParentData($blLoadParentData)
00771     {
00772         $this->_blLoadParentData = $blLoadParentData;
00773     }
00774 
00780     public function getLoadParentData()
00781     {
00782         return $this->_blLoadParentData;
00783     }
00784 
00785 
00793     public function isMultilingualField($sFieldName)
00794     {
00795         switch ($sFieldName) {
00796             case "oxlongdesc":
00797             case "oxtags":
00798                 return true;
00799         }
00800 
00801         return parent::isMultilingualField($sFieldName);
00802     }
00803 
00810     public function getFUnitPrice()
00811     {
00812         if ($this->_fPricePerUnit == null) {
00813             if ($oPrice = $this->getUnitPrice()) {
00814                 if ($dPrice = $this->_getPriceForView($oPrice)) {
00815                     $this->_fPricePerUnit = oxRegistry::getLang()->formatCurrency($dPrice);
00816                 }
00817             }
00818         }
00819 
00820         return $this->_fPricePerUnit;
00821     }
00822 
00828     public function getUnitPrice()
00829     {
00830         // Performance
00831         if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
00832             return;
00833         }
00834 
00835         $oPrice = null;
00836         if ((double) $this->getUnitQuantity() && $this->oxarticles__oxunitname->value) {
00837             $oPrice = clone $this->getPrice();
00838             $oPrice->divide((double) $this->getUnitQuantity());
00839         }
00840 
00841         return $oPrice;
00842     }
00843 
00851     public function getFMinPrice()
00852     {
00853         $sPrice = '';
00854         if ($oPrice = $this->getMinPrice()) {
00855             $dPrice = $this->_getPriceForView($oPrice);
00856             $sPrice = oxRegistry::getLang()->formatCurrency($dPrice);
00857         }
00858 
00859         return $sPrice;
00860     }
00861 
00869     public function getFVarMinPrice()
00870     {
00871         $sPrice = '';
00872         if ($oPrice = $this->getVarMinPrice()) {
00873             $dPrice = $this->_getPriceForView($oPrice);
00874             $sPrice = oxRegistry::getLang()->formatCurrency($dPrice);
00875         }
00876 
00877         return $sPrice;
00878     }
00879 
00885     public function getVarMinPrice()
00886     {
00887         if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
00888             return;
00889         }
00890 
00891         $oPrice = null;
00892         $dPrice = $this->_getVarMinPrice();
00893 
00894         $dPrice = $this->_preparePrice($dPrice, $this->getArticleVat());
00895 
00896 
00897         $oPrice = $this->_getPriceObject();
00898         $oPrice->setPrice($dPrice);
00899         $this->_calculatePrice($oPrice);
00900 
00901 
00902         return $oPrice;
00903     }
00904 
00910     public function getMinPrice()
00911     {
00912         if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
00913             return;
00914         }
00915 
00916         $oPrice = null;
00917         $dPrice = $this->_getPrice();
00918         if ($this->_getVarMinPrice() !== null && $dPrice > $this->_getVarMinPrice()) {
00919             $dPrice = $this->_getVarMinPrice();
00920         }
00921 
00922         $dPrice = $this->_preparePrice($dPrice, $this->getArticleVat());
00923 
00924 
00925         $oPrice = $this->_getPriceObject();
00926         $oPrice->setPrice($dPrice);
00927         $this->_calculatePrice($oPrice);
00928 
00929         return $oPrice;
00930     }
00931 
00937     public function isRangePrice()
00938     {
00939         if ($this->_blIsRangePrice === null) {
00940 
00941             $this->setRangePrice(false);
00942 
00943             if ($this->_hasAnyVariant()) {
00944                 $dPrice = $this->_getPrice();
00945                 $dMinPrice = $this->_getVarMinPrice();
00946                 $dMaxPrice = $this->_getVarMaxPrice();
00947 
00948                 if ($dMinPrice != $dMaxPrice) {
00949                     $this->setRangePrice();
00950                 } elseif (!$this->isParentNotBuyable() && $dMinPrice != $dPrice) {
00951                     $this->setRangePrice();
00952                 }
00953             }
00954         }
00955 
00956         return $this->_blIsRangePrice;
00957     }
00958 
00959 
00967     public function setRangePrice($blIsRangePrice = true)
00968     {
00969         return $this->_blIsRangePrice = $blIsRangePrice;
00970     }
00971 
00977     public function isVisible()
00978     {
00979 
00980         // admin preview mode
00981         if (($blCanPreview = oxRegistry::getUtils()->canPreview()) !== null) {
00982             return $blCanPreview;
00983         }
00984 
00985         // active ?
00986         $sNow = date('Y-m-d H:i:s');
00987         if (!$this->oxarticles__oxactive->value &&
00988             ($this->oxarticles__oxactivefrom->value > $sNow ||
00989              $this->oxarticles__oxactiveto->value < $sNow
00990             )
00991         ) {
00992             return false;
00993         }
00994 
00995         // stock flags
00996         if ($this->getConfig()->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2) {
00997             $iOnStock = $this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value;
00998             if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
00999                 $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
01000             }
01001             if ($iOnStock <= 0) {
01002                 return false;
01003             }
01004         }
01005 
01006         return true;
01007     }
01008 
01017     public function assign($aRecord)
01018     {
01019         startProfile('articleAssign');
01020 
01021         // load object from database
01022         parent::assign($aRecord);
01023 
01024         $this->oxarticles__oxnid = $this->oxarticles__oxid;
01025 
01026         // check for simple article.
01027         if ($this->_blSkipAssign) {
01028             return;
01029         }
01030 
01031         $this->_assignParentFieldValues();
01032         $this->_assignNotBuyableParent();
01033 
01034 
01035         $this->_assignStock();
01036         $this->_assignPersistentParam();
01037         $this->_assignDynImageDir();
01038         $this->_assignComparisonListFlag();
01039 
01040 
01041         stopProfile('articleAssign');
01042     }
01043 
01044 
01055     public function load($sOXID)
01056     {
01057         // A. #1325 resetting to avoid problems when reloading (details etc)
01058         $this->_blNotBuyableParent = false;
01059 
01060 
01061         $aData = $this->_loadFromDb($sOXID);
01062 
01063         if ($aData) {
01064             $this->assign($aData);
01065 
01066             $this->_saveSortingFieldValuesOnLoad();
01067 
01068             $this->_iStockStatusOnLoad = $this->_iStockStatus;
01069 
01070             $this->_isLoaded = true;
01071 
01072             return true;
01073         }
01074 
01075         return false;
01076     }
01077 
01083     public function hasSortingFieldsChanged()
01084     {
01085         $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
01086         $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
01087         $blChanged = false;
01088         foreach ($aSortingFields as $sField) {
01089             $sParameterName = 'oxarticles__' . $sField;
01090             if ($this->$sParameterName->value !== $this->_aSortingFieldsOnLoad[$sParameterName]) {
01091                 $blChanged = true;
01092                 break;
01093             }
01094         }
01095 
01096         return $blChanged;
01097     }
01098 
01099 
01105     public function addToRatingAverage($iRating)
01106     {
01107         $dOldRating = $this->oxarticles__oxrating->value;
01108         $dOldCnt = $this->oxarticles__oxratingcnt->value;
01109         $this->oxarticles__oxrating->setValue(($dOldRating * $dOldCnt + $iRating) / ($dOldCnt + 1));
01110         $this->oxarticles__oxratingcnt->setValue($dOldCnt + 1);
01111         $dRating = ($dOldRating * $dOldCnt + $iRating) / ($dOldCnt + 1);
01112         $dRatingCnt = (int) ($dOldCnt + 1);
01113         // oxarticles.oxtimestamp = oxarticles.oxtimestamp to keep old timestamp value
01114         $oDb = oxDb::getDb();
01115         $oDb->execute('update oxarticles set oxarticles.oxrating = ' . $dRating . ',oxarticles.oxratingcnt = ' . $dRatingCnt . ', oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = ' . $oDb->quote($this->getId()));
01116 
01117     }
01118 
01124     public function setRatingAverage($iRating)
01125     {
01126         $this->oxarticles__oxrating = new oxField($iRating);
01127     }
01128 
01134     public function setRatingCount($iRatingCnt)
01135     {
01136         $this->oxarticles__oxratingcnt = new oxField($iRatingCnt);
01137     }
01138 
01146     public function getArticleRatingAverage($blIncludeVariants = false)
01147     {
01148         if (!$blIncludeVariants) {
01149             return round($this->oxarticles__oxrating->value, 1);
01150         } else {
01151             $oRating = oxNew('oxRating');
01152 
01153             return $oRating->getRatingAverage($this->getId(), 'oxarticle', $this->_getVariantsIds());
01154         }
01155     }
01156 
01164     public function getArticleRatingCount($blIncludeVariants = false)
01165     {
01166         if (!$blIncludeVariants) {
01167             return $this->oxarticles__oxratingcnt->value;
01168         } else {
01169             $oRating = oxNew('oxRating');
01170 
01171             return $oRating->getRatingCount($this->getId(), 'oxarticle', $this->_getVariantsIds());
01172         }
01173     }
01174 
01175 
01181     public function getReviews()
01182     {
01183         $aIds = array($this->getId());
01184 
01185         if ($this->oxarticles__oxparentid->value) {
01186             $aIds[] = $this->oxarticles__oxparentid->value;
01187         }
01188 
01189         // showing variant reviews ..
01190         if ($this->getConfig()->getConfigParam('blShowVariantReviews')) {
01191             $aAdd = $this->_getVariantsIds();
01192             if (is_array($aAdd)) {
01193                 $aIds = array_merge($aIds, $aAdd);
01194             }
01195         }
01196 
01197         $oReview = oxNew('oxreview');
01198         $oRevs = $oReview->loadList('oxarticle', $aIds);
01199 
01200         //if no review found, return null
01201         if ($oRevs->count() < 1) {
01202             return null;
01203         }
01204 
01205         return $oRevs;
01206     }
01207 
01213     public function getCrossSelling()
01214     {
01215         $oCrosslist = oxNew("oxarticlelist");
01216         $oCrosslist->loadArticleCrossSell($this->oxarticles__oxid->value);
01217         if ($oCrosslist->count()) {
01218             return $oCrosslist;
01219         }
01220     }
01221 
01227     public function getAccessoires()
01228     {
01229         $myConfig = $this->getConfig();
01230 
01231         // Performance
01232         if (!$myConfig->getConfigParam('bl_perfLoadAccessoires')) {
01233             return;
01234         }
01235 
01236         $oAcclist = oxNew("oxarticlelist");
01237         $oAcclist->setSqlLimit(0, $myConfig->getConfigParam('iNrofCrossellArticles'));
01238         $oAcclist->loadArticleAccessoires($this->oxarticles__oxid->value);
01239 
01240         if ($oAcclist->count()) {
01241             return $oAcclist;
01242         }
01243     }
01244 
01250     public function getSimilarProducts()
01251     {
01252         // Performance
01253         $myConfig = $this->getConfig();
01254         if (!$myConfig->getConfigParam('bl_perfLoadSimilar')) {
01255             return;
01256         }
01257 
01258         $sArticleTable = $this->getViewName();
01259 
01260         $sAttribs = '';
01261         $iCnt = 0;
01262         $this->_getAttribsString($sAttribs, $iCnt);
01263 
01264         if (!$sAttribs) {
01265             return null;
01266         }
01267 
01268         $aList = $this->_getSimList($sAttribs, $iCnt);
01269 
01270         if (count($aList)) {
01271             uasort($aList, 'cmpart');
01272 
01273             $sSearch = $this->_generateSimListSearchStr($sArticleTable, $aList);
01274 
01275             $oSimilarlist = oxNew('oxarticlelist');
01276             $oSimilarlist->setSqlLimit(0, $myConfig->getConfigParam('iNrofSimilarArticles'));
01277             $oSimilarlist->selectString($sSearch);
01278 
01279             return $oSimilarlist;
01280         }
01281     }
01282 
01288     public function getCustomerAlsoBoughtThisProducts()
01289     {
01290         // Performance
01291         $myConfig = $this->getConfig();
01292         if (!$myConfig->getConfigParam('bl_perfLoadCustomerWhoBoughtThis')) {
01293             return;
01294         }
01295 
01296         // selecting products that fits
01297         $sQ = $this->_generateSearchStrForCustomerBought();
01298 
01299         $oArticles = oxNew('oxarticlelist');
01300         $oArticles->setSqlLimit(0, $myConfig->getConfigParam('iNrofCustomerWhoArticles'));
01301         $oArticles->selectString($sQ);
01302         if ($oArticles->count()) {
01303             return $oArticles;
01304         }
01305     }
01306 
01313     public function loadAmountPriceInfo()
01314     {
01315         $myConfig = $this->getConfig();
01316         if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice || !$this->_blCalcPrice || !$this->hasAmountPrice()) {
01317             return array();
01318         }
01319 
01320         if ($this->_oAmountPriceInfo === null) {
01321             $this->_oAmountPriceInfo = array();
01322             if (count(($aAmPriceList = $this->_getAmountPriceList()->getArray()))) {
01323                 $this->_oAmountPriceInfo = $this->_fillAmountPriceList($aAmPriceList);
01324             }
01325         }
01326 
01327         return $this->_oAmountPriceInfo;
01328     }
01329 
01337     public function getSelectLists($sKeyPrefix = null)
01338     {
01339         //#1468C - more then one article in basket with different selectlist...
01340         //optionall function parameter $sKeyPrefix added, used only in basket.php
01341         $sKey = $this->getId();
01342         if (isset($sKeyPrefix)) {
01343             $sKey = $sKeyPrefix . '__' . $sKey;
01344         }
01345 
01346         if (!isset(self::$_aSelList[$sKey])) {
01347             $oDb = oxDb::getDb();
01348             $sSLViewName = getViewName('oxselectlist');
01349 
01350             $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
01351                    where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
01352 
01353             // all selectlists this article has
01354             $oLists = oxNew('oxlist');
01355             $oLists->init('oxselectlist');
01356             $oLists->selectString(sprintf($sQ, $oDb->quote($this->getId())));
01357 
01358             //#1104S if this is variant ant it has no selectlists, trying with parent
01359             if ($oLists->count() == 0 && $this->oxarticles__oxparentid->value) {
01360                 $oLists->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
01361             }
01362 
01363             // We do not need to calculate price here as there are method to get current article vat
01364             /*if ( $this->getPrice() != null ) {
01365                 $dVat = $this->getPrice()->getVat();
01366             }*/
01367             $dVat = $this->getArticleVat();
01368 
01369             $iCnt = 0;
01370             self::$_aSelList[$sKey] = array();
01371             foreach ($oLists as $oSelectlist) {
01372                 self::$_aSelList[$sKey][$iCnt] = $oSelectlist->getFieldList($dVat);
01373                 self::$_aSelList[$sKey][$iCnt]['name'] = $oSelectlist->oxselectlist__oxtitle->value;
01374                 $iCnt++;
01375             }
01376         }
01377 
01378         return self::$_aSelList[$sKey];
01379     }
01380 
01386     public function getVariantsCount()
01387     {
01388         return $this->oxarticles__oxvarcount->value;
01389     }
01390 
01396     public function hasMdVariants()
01397     {
01398         return $this->_blHasMdVariants;
01399     }
01400 
01406     public function hasIntangibleAgreement()
01407     {
01408         return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxnonmaterial->value && !$this->hasDownloadableAgreement();
01409     }
01410 
01416     public function hasDownloadableAgreement()
01417     {
01418         return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxisdownloadable->value;
01419     }
01420 
01430     public function getVariantSelections($aFilterIds = null, $sActVariantId = null, $iLimit = 0)
01431     {
01432         $iLimit = (int) $iLimit;
01433         if (!isset($this->_aVariantSelections[$iLimit])) {
01434             $aVariantSelections = false;
01435             if ($this->oxarticles__oxvarcount->value) {
01436                 $oVariants = $this->getVariants(false);
01437                 $aVariantSelections = oxNew("oxVariantHandler")->buildVariantSelections($this->oxarticles__oxvarname->getRawValue(), $oVariants, $aFilterIds, $sActVariantId, $iLimit);
01438 
01439                 if (!empty($oVariants) && empty($aVariantSelections['rawselections'])) {
01440                     $aVariantSelections = false;
01441                 }
01442             }
01443             $this->_aVariantSelections[$iLimit] = $aVariantSelections;
01444         }
01445 
01446         return $this->_aVariantSelections[$iLimit];
01447     }
01448 
01457     public function getSelections($iLimit = null, $aFilter = null)
01458     {
01459         $sId = $this->getId() . ((int) $iLimit);
01460         if (!array_key_exists($sId, self::$_aSelections)) {
01461 
01462             $oDb = oxDb::getDb();
01463             $sSLViewName = getViewName('oxselectlist');
01464 
01465             $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
01466                    where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
01467 
01468             if (($iLimit = (int) $iLimit)) {
01469                 $sQ .= " limit $iLimit ";
01470             }
01471 
01472             // vat value for price
01473             $dVat = 0;
01474             if (($oPrice = $this->getPrice()) != null) {
01475                 $dVat = $oPrice->getVat();
01476             }
01477 
01478             // all selectlists this article has
01479             $oList = oxNew('oxlist');
01480             $oList->init('oxselectlist');
01481             $oList->getBaseObject()->setVat($dVat);
01482             $oList->selectString(sprintf($sQ, $oDb->quote($this->getId())));
01483 
01484             //#1104S if this is variant and it has no selectlists, trying with parent
01485             if ($oList->count() == 0 && $this->oxarticles__oxparentid->value) {
01486                 $oList->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
01487             }
01488 
01489             self::$_aSelections[$sId] = $oList->count() ? $oList : false;
01490         }
01491 
01492         if (self::$_aSelections[$sId]) {
01493             // marking active from filter
01494             $aFilter = ($aFilter === null) ? oxRegistry::getConfig()->getRequestParameter("sel") : $aFilter;
01495             if ($aFilter) {
01496                 $iSelIdx = 0;
01497                 foreach (self::$_aSelections[$sId] as $oSelection) {
01498                     if (isset($aFilter[$iSelIdx])) {
01499                         $oSelection->setActiveSelectionByIndex($aFilter[$iSelIdx]);
01500                     }
01501                     $iSelIdx++;
01502                 }
01503             }
01504         }
01505 
01506         return self::$_aSelections[$sId];
01507     }
01508 
01517     public function getFullVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
01518     {
01519         return $this->_loadVariantList(false, $blRemoveNotOrderables, $blForceCoreTable);
01520     }
01521 
01531     public function getVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
01532     {
01533         return $this->_loadVariantList($this->_isInList(), $blRemoveNotOrderables, $blForceCoreTable);
01534     }
01535 
01541     public function getSimpleVariants()
01542     {
01543         if ($this->oxarticles__oxvarcount->value) {
01544             return $this->getVariants();
01545         }
01546     }
01547 
01556     public function getAdminVariants($sLanguage = null)
01557     {
01558         $oVariants = oxNew('oxarticlelist');
01559         if (($sId = $this->getId())) {
01560 
01561             $oBaseObj = $oVariants->getBaseObject();
01562 
01563             if (is_null($sLanguage)) {
01564                 $oBaseObj->setLanguage(oxRegistry::getLang()->getBaseLanguage());
01565             } else {
01566                 $oBaseObj->setLanguage($sLanguage);
01567             }
01568 
01569             $sSql = "select * from " . $oBaseObj->getViewName() . " where oxparentid = '{$sId}' order by oxsort ";
01570             $oVariants->selectString($sSql);
01571 
01572             //if we have variants then depending on config option the parent may be non buyable
01573             if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && ($oVariants->count() > 0)) {
01574                 //$this->blNotBuyable = true;
01575                 $this->_blNotBuyableParent = true;
01576             }
01577         }
01578 
01579         return $oVariants;
01580     }
01581 
01589     public function getCategory()
01590     {
01591         $oCategory = oxNew('oxcategory');
01592         $oCategory->setLanguage($this->getLanguage());
01593 
01594         // variant handling
01595         $sOXID = $this->getId();
01596         if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01597             $sOXID = $this->oxarticles__oxparentid->value;
01598         }
01599 
01600         if ($sOXID) {
01601             // if the oxcategory instance of this article is not cached
01602             if (!isset($this->_aCategoryCache[$sOXID])) {
01603                 startPRofile('getCategory');
01604                 $oStr = getStr();
01605                 $sWhere = $oCategory->getSqlActiveSnippet();
01606                 $sSelect = $this->_generateSearchStr($sOXID);
01607                 $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " order by oxobject2category.oxtime limit 1";
01608 
01609                 // category not found ?
01610                 if (!$oCategory->assignRecord($sSelect)) {
01611 
01612                     $sSelect = $this->_generateSearchStr($sOXID, true);
01613                     $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " limit 1";
01614 
01615                     // looking for price category
01616                     if (!$oCategory->assignRecord($sSelect)) {
01617                         $oCategory = null;
01618                     }
01619                 }
01620                 // add the category instance to cache
01621                 $this->_aCategoryCache[$sOXID] = $oCategory;
01622                 stopPRofile('getCategory');
01623             } else {
01624                 // if the oxcategory instance is cached
01625                 $oCategory = $this->_aCategoryCache[$sOXID];
01626             }
01627         }
01628 
01629         return $oCategory;
01630     }
01631 
01640     public function getCategoryIds($blActCats = false, $blSkipCache = false)
01641     {
01642         $sArticleId = $this->getId();
01643 
01644         if (!isset(self::$_aArticleCats[$sArticleId]) || $blSkipCache) {
01645 
01646             $sSql = $this->_getCategoryIdsSelect($blActCats);
01647             $aCategoryIds = $this->_selectCategoryIds($sSql, 'oxcatnid');
01648 
01649             $sSql = $this->getSqlForPriceCategories();
01650             $aPriceCategoryIds = $this->_selectCategoryIds($sSql, 'oxid');
01651 
01652             self::$_aArticleCats[$sArticleId] = array_unique(array_merge($aCategoryIds, $aPriceCategoryIds));
01653         }
01654 
01655         return self::$_aArticleCats[$sArticleId];
01656     }
01657 
01667     public function getVendor($blShopCheck = true)
01668     {
01669         if (($sVendorId = $this->getVendorId())) {
01670             $oVendor = oxNew('oxvendor');
01671         } elseif (!$blShopCheck && $this->oxarticles__oxvendorid->value) {
01672             $oVendor = oxNew('oxi18n');
01673             $oVendor->init('oxvendor');
01674             $oVendor->setReadOnly(true);
01675             $sVendorId = $this->oxarticles__oxvendorid->value;
01676         }
01677         if ($sVendorId && $oVendor->load($sVendorId) && $oVendor->oxvendor__oxactive->value) {
01678 
01679             return $oVendor;
01680         }
01681 
01682         return null;
01683     }
01684 
01692     public function getVendorId($blForceReload = false)
01693     {
01694         $sVendorId = false;
01695         if ($this->oxarticles__oxvendorid->value) {
01696             $sVendorId = $this->oxarticles__oxvendorid->value;
01697 
01698         }
01699 
01700         return $sVendorId;
01701     }
01702 
01710     public function getManufacturerId($blForceReload = false)
01711     {
01712         $sManufacturerId = false;
01713         if ($this->oxarticles__oxmanufacturerid->value) {
01714 
01715             $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
01716 
01717         }
01718 
01719         return $sManufacturerId;
01720     }
01721 
01731     public function getManufacturer($blShopCheck = true)
01732     {
01733         $oManufacturer = oxNew('oxmanufacturer');
01734         if (!($sManufacturerId = $this->getManufacturerId()) &&
01735             !$blShopCheck && $this->oxarticles__oxmanufacturerid->value
01736         ) {
01737             $oManufacturer->setReadOnly(true);
01738             $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
01739         }
01740 
01741         if ($sManufacturerId && $oManufacturer->load($sManufacturerId)) {
01742             if (!$this->getConfig()->getConfigParam('bl_perfLoadManufacturerTree')) {
01743                 $oManufacturer->setReadOnly(true);
01744             }
01745             $oManufacturer = $oManufacturer->oxmanufacturers__oxactive->value ? $oManufacturer : null;
01746         } else {
01747             $oManufacturer = null;
01748         }
01749 
01750         return $oManufacturer;
01751     }
01752 
01760     public function inCategory($sCatNid)
01761     {
01762         return in_array($sCatNid, $this->getCategoryIds());
01763     }
01764 
01773     public function isAssignedToCategory($sCatId)
01774     {
01775         // variant handling
01776         $sOXID = $this->getId();
01777         if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01778             $sOXID = $this->oxarticles__oxparentid->value;
01779         }
01780 
01781         $oDb = oxDb::getDb();
01782         $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId);
01783         $sOXID = $oDb->getOne($sSelect);
01784         // article is assigned to passed category!
01785         if (isset($sOXID) && $sOXID) {
01786             return true;
01787         }
01788 
01789         // maybe this category is price category ?
01790         if ($this->getConfig()->getConfigParam('bl_perfLoadPrice') && $this->_blLoadPrice) {
01791             $dPriceFromTo = $this->getPrice()->getBruttoPrice();
01792             if ($dPriceFromTo > 0) {
01793                 $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo);
01794                 $sOXID = $oDb->getOne($sSelect);
01795                 // article is assigned to passed category!
01796                 if (isset($sOXID) && $sOXID) {
01797                     return true;
01798                 }
01799             }
01800         }
01801 
01802         return false;
01803     }
01804 
01810     public function getTPrice()
01811     {
01812         if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
01813             return;
01814         }
01815 
01816         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01817         if ($this->_oTPrice !== null) {
01818             return $this->_oTPrice;
01819         }
01820 
01821         $oPrice = $this->_getPriceObject();
01822 
01823         $dBasePrice = $this->oxarticles__oxtprice->value;
01824         $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
01825 
01826         $oPrice->setPrice($dBasePrice);
01827 
01828         $this->_applyVat($oPrice, $this->getArticleVat());
01829         $this->_applyCurrency($oPrice);
01830 
01831         if ($this->isParentNotBuyable()) {
01832             // if parent article is not buyable then compare agains min article variant price
01833             $oPrice2 = $this->getVarMinPrice();
01834         } else {
01835             // else compare against article price
01836             $oPrice2 = $this->getPrice();
01837         }
01838 
01839         if ($oPrice->getPrice() <= $oPrice2->getPrice()) {
01840             // if RRP price is less or equal to comparable price then return
01841             return;
01842         }
01843 
01844         $this->_oTPrice = $oPrice;
01845 
01846         return $this->_oTPrice;
01847     }
01848 
01854     public function skipDiscounts()
01855     {
01856         // already loaded skip discounts config
01857         if ($this->_blSkipDiscounts !== null) {
01858             return $this->_blSkipDiscounts;
01859         }
01860 
01861         if ($this->oxarticles__oxskipdiscounts->value) {
01862             return true;
01863         }
01864 
01865 
01866         $this->_blSkipDiscounts = false;
01867         if (oxRegistry::get("oxDiscountList")->hasSkipDiscountCategories()) {
01868 
01869             $oDb = oxDb::getDb();
01870             $sO2CView = getViewName('oxobject2category', $this->getLanguage());
01871             $sViewName = getViewName('oxcategories', $this->getLanguage());
01872             $sSelect = "select 1 from $sO2CView as $sO2CView left join {$sViewName} on {$sViewName}.oxid = $sO2CView.oxcatnid
01873                          where $sO2CView.oxobjectid=" . $oDb->quote($this->getId()) . " and {$sViewName}.oxactive = 1 and {$sViewName}.oxskipdiscounts = '1' ";
01874             $this->_blSkipDiscounts = ($oDb->getOne($sSelect) == 1);
01875         }
01876 
01877         return $this->_blSkipDiscounts;
01878     }
01879 
01885     public function setPrice(oxPrice $oPrice)
01886     {
01887         $this->_oPrice = $oPrice;
01888     }
01889 
01898     public function getBasePrice($dAmount = 1)
01899     {
01900         // override this function if you want e.g. different prices
01901         // for diff. user groups.
01902 
01903         // Performance
01904         $myConfig = $this->getConfig();
01905         if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
01906             return;
01907         }
01908 
01909         // GroupPrice or DB price ajusted by AmountPrice
01910         $dPrice = $this->_getAmountPrice($dAmount);
01911 
01912 
01913         return $dPrice;
01914     }
01915 
01923     public function getPrice($dAmount = 1)
01924     {
01925         $myConfig = $this->getConfig();
01926         // Performance
01927         if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
01928             return;
01929         }
01930 
01931         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01932         if ($dAmount != 1 || $this->_oPrice === null) {
01933 
01934             // module
01935             $dBasePrice = $this->getBasePrice($dAmount);
01936             $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
01937 
01938             $oPrice = $this->_getPriceObject();
01939 
01940             $oPrice->setPrice($dBasePrice);
01941 
01942             // price handling
01943             if (!$this->_blCalcPrice && $dAmount == 1) {
01944                 return $this->_oPrice = $oPrice;
01945             }
01946 
01947             $this->_calculatePrice($oPrice);
01948             if ($dAmount != 1) {
01949                 return $oPrice;
01950             }
01951 
01952             $this->_oPrice = $oPrice;
01953         }
01954 
01955         return $this->_oPrice;
01956     }
01957 
01963     public function setArticleUser($oUser)
01964     {
01965         $this->_oUser = $oUser;
01966     }
01967 
01973     public function getArticleUser()
01974     {
01975         if ($this->_oUser) {
01976             return $this->_oUser;
01977         }
01978 
01979         return $this->getUser();
01980     }
01981 
01991     public function getBasketPrice($dAmount, $aSelList, $oBasket)
01992     {
01993         $oUser = $oBasket->getBasketUser();
01994         $this->setArticleUser($oUser);
01995 
01996         $oBasketPrice = $this->_getPriceObject($oBasket->isCalculationModeNetto());
01997 
01998         // get base price
01999         $dBasePrice = $this->getBasePrice($dAmount);
02000 
02001         $dBasePrice = $this->_modifySelectListPrice($dBasePrice, $aSelList);
02002         $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat(), $oBasket->isCalculationModeNetto());
02003 
02004         // applying select list price
02005 
02006         // setting price
02007         $oBasketPrice->setPrice($dBasePrice);
02008 
02009         $dVat = oxRegistry::get("oxVatSelector")->getBasketItemVat($this, $oBasket);
02010         $this->_calculatePrice($oBasketPrice, $dVat);
02011 
02012         // returning final price object
02013         return $oBasketPrice;
02014     }
02015 
02024     public function delete($sOXID = null)
02025     {
02026         if (!$sOXID) {
02027             $sOXID = $this->getId();
02028         }
02029         if (!$sOXID) {
02030             return false;
02031         }
02032 
02033 
02034 
02035         // #2339 delete first variants before deleting parent product
02036         $this->_deleteVariantRecords($sOXID);
02037         $this->load($sOXID);
02038         $this->_deletePics();
02039         $this->_onChangeResetCounts($sOXID, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
02040 
02041         // delete self
02042         parent::delete($sOXID);
02043 
02044         $rs = $this->_deleteRecords($sOXID);
02045 
02046         oxRegistry::get("oxSeoEncoderArticle")->onDeleteArticle($this);
02047 
02048         $this->onChange(ACTION_DELETE, $sOXID, $this->oxarticles__oxparentid->value);
02049 
02050         return $rs->EOF;
02051     }
02052 
02061     public function reduceStock($dAmount, $blAllowNegativeStock = false)
02062     {
02063         $this->beforeUpdate();
02064 
02065         $iStockCount = $this->oxarticles__oxstock->value - $dAmount;
02066         if (!$blAllowNegativeStock && ($iStockCount < 0)) {
02067             $dAmount += $iStockCount;
02068             $iStockCount = 0;
02069         }
02070         $this->oxarticles__oxstock = new oxField($iStockCount);
02071 
02072         $oDb = oxDb::getDb();
02073         $oDb->execute('update oxarticles set oxarticles.oxstock = ' . $oDb->quote($iStockCount) . ' where oxarticles.oxid = ' . $oDb->quote($this->getId()));
02074         $this->onChange(ACTION_UPDATE_STOCK);
02075 
02076         return $dAmount;
02077     }
02078 
02087     public function updateSoldAmount($dAmount = 0)
02088     {
02089         if (!$dAmount) {
02090             return;
02091         }
02092 
02093         // article is not variant - should be updated current amount
02094         if (!$this->oxarticles__oxparentid->value) {
02095             //updating by SQL query, due to wrong behaviour if saving article using not admin mode
02096             $dAmount = (double) $dAmount;
02097             $oDb = oxDb::getDb();
02098             $rs = $oDb->execute("update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $dAmount where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
02099         } elseif ($this->oxarticles__oxparentid->value) {
02100             // article is variant - should be updated this article parent amount
02101             $oUpdateArticle = $this->getParentArticle();
02102             if ($oUpdateArticle) {
02103                 $oUpdateArticle->updateSoldAmount($dAmount);
02104             }
02105         }
02106 
02107         return $rs;
02108     }
02109 
02115     public function disableReminder()
02116     {
02117         $oDb = oxDb::getDb();
02118 
02119         return $oDb->execute("update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
02120     }
02121 
02127     public function save()
02128     {
02129         $this->_assignParentDependFields();
02130 
02131         if (($blRet = parent::save())) {
02132             // saving long description
02133             $this->_saveArtLongDesc();
02134         }
02135 
02136         return $blRet;
02137     }
02138 
02142     public function resetParent()
02143     {
02144         $sParentId = $this->oxarticles__oxparentid->value;
02145         $this->oxarticles__oxparentid = new oxField('', oxField::T_RAW);
02146         $this->_blAllowEmptyParentId = true;
02147         $this->save();
02148         $this->_blAllowEmptyParentId = false;
02149 
02150         if ($sParentId !== '') {
02151             $this->onChange(ACTION_UPDATE, null, $sParentId);
02152         }
02153     }
02154 
02155 
02162     public function getPictureGallery()
02163     {
02164         $myConfig = $this->getConfig();
02165 
02166         //initialize
02167         $blMorePic = false;
02168         $aArtPics = array();
02169         $aArtIcons = array();
02170         $iActPicId = 1;
02171         $sActPic = $this->getPictureUrl($iActPicId);
02172 
02173         if (oxRegistry::getConfig()->getRequestParameter('actpicid')) {
02174             $iActPicId = oxRegistry::getConfig()->getRequestParameter('actpicid');
02175         }
02176 
02177         $oStr = getStr();
02178         $iCntr = 0;
02179         $iPicCount = $myConfig->getConfigParam('iPicCount');
02180         $blCheckActivePicId = true;
02181 
02182         for ($i = 1; $i <= $iPicCount; $i++) {
02183             $sPicVal = $this->getPictureUrl($i);
02184             $sIcoVal = $this->getIconUrl($i);
02185             if (!$oStr->strstr($sIcoVal, 'nopic_ico.jpg') && !$oStr->strstr($sIcoVal, 'nopic.jpg') &&
02186                 !$oStr->strstr($sPicVal, 'nopic_ico.jpg') && !$oStr->strstr($sPicVal, 'nopic.jpg')
02187             ) {
02188                 if ($iCntr) {
02189                     $blMorePic = true;
02190                 }
02191                 $aArtIcons[$i] = $sIcoVal;
02192                 $aArtPics[$i] = $sPicVal;
02193                 $iCntr++;
02194 
02195                 if ($iActPicId == $i) {
02196                     $sActPic = $sPicVal;
02197                     $blCheckActivePicId = false;
02198                 }
02199 
02200             } elseif ($blCheckActivePicId && $iActPicId <= $i) {
02201                 // if picture is empty, setting active pic id to next
02202                 // picture
02203                 $iActPicId++;
02204             }
02205         }
02206 
02207         $blZoomPic = false;
02208         $aZoomPics = array();
02209         $iZoomPicCount = $myConfig->getConfigParam('iPicCount');
02210 
02211         for ($j = 1, $c = 1; $j <= $iZoomPicCount; $j++) {
02212             $sVal = $this->getZoomPictureUrl($j);
02213 
02214             if ($sVal && !$oStr->strstr($sVal, 'nopic.jpg')) {
02215                 $blZoomPic = true;
02216                 $aZoomPics[$c]['id'] = $c;
02217                 $aZoomPics[$c]['file'] = $sVal;
02218                 //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
02219                 if (!$sVal) {
02220                     $aZoomPics[$c]['file'] = "nopic.jpg";
02221                 }
02222                 $c++;
02223             }
02224         }
02225 
02226         $aPicGallery = array('ActPicID' => $iActPicId,
02227                              'ActPic'   => $sActPic,
02228                              'MorePics' => $blMorePic,
02229                              'Pics'     => $aArtPics,
02230                              'Icons'    => $aArtIcons,
02231                              'ZoomPic'  => $blZoomPic,
02232                              'ZoomPics' => $aZoomPics);
02233 
02234         return $aPicGallery;
02235     }
02236 
02250     public function onChange($sAction = null, $sOXID = null, $sParentID = null)
02251     {
02252         $myConfig = $this->getConfig();
02253 
02254         if (!isset($sOXID)) {
02255             if ($this->getId()) {
02256                 $sOXID = $this->getId();
02257             }
02258             if (!isset ($sOXID)) {
02259                 $sOXID = $this->oxarticles__oxid->value;
02260             }
02261             if ($this->oxarticles__oxparentid->value) {
02262                 $sParentID = $this->oxarticles__oxparentid->value;
02263             }
02264         }
02265         if (!isset($sOXID)) {
02266             return;
02267         }
02268 
02269         //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
02270         if ($myConfig->getConfigParam('blUseStock')) {
02271             //if article has variants then updating oxvarstock field
02272             //getting parent id
02273             if (!isset($sParentID)) {
02274                 $oDb = oxDb::getDb();
02275                 $sQ = 'select oxparentid from oxarticles where oxid = ' . $oDb->quote($sOXID);
02276                 $sParentID = $oDb->getOne($sQ);
02277             }
02278             //if we have parent id then update stock
02279             if ($sParentID) {
02280                 $this->_onChangeUpdateStock($sParentID);
02281             }
02282         }
02283         //if we have parent id then update count
02284         //update count even if blUseStock is not active
02285         if ($sParentID) {
02286             $this->_onChangeUpdateVarCount($sParentID);
02287         }
02288 
02289         $sId = ($sParentID) ? $sParentID : $sOXID;
02290         $this->_setVarMinMaxPrice($sId);
02291 
02292         $this->_updateParentDependFields();
02293 
02294         // resetting articles count cache if stock has changed and some
02295         // articles goes offline (M:1448)
02296         if ($sAction === ACTION_UPDATE_STOCK) {
02297             $this->_assignStock();
02298             $this->_onChangeStockResetCount($sOXID);
02299         }
02300 
02301     }
02302 
02309     public function getCustomVAT()
02310     {
02311         if (isset($this->oxarticles__oxvat->value)) {
02312             return $this->oxarticles__oxvat->value;
02313         }
02314     }
02315 
02324     public function checkForStock($dAmount, $dArtStockAmount = 0)
02325     {
02326         $myConfig = $this->getConfig();
02327         if (!$myConfig->getConfigParam('blUseStock')) {
02328             return true;
02329         }
02330 
02331         $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
02332         // fetching DB info as its up-to-date
02333         $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = ' . $oDb->quote($this->getId());
02334         $rs = $oDb->select($sQ);
02335 
02336         $iOnStock = 0;
02337         $iStockFlag = 0;
02338         if ($rs !== false && $rs->recordCount() > 0) {
02339             $iOnStock = $rs->fields['oxstock'] - $dArtStockAmount;
02340             $iStockFlag = $rs->fields['oxstockflag'];
02341 
02342             // foreign stock is also always considered as on stock
02343             if ($iStockFlag == 1 || $iStockFlag == 4) {
02344                 return true;
02345             }
02346             if (!$myConfig->getConfigParam('blAllowUnevenAmounts')) {
02347                 $iOnStock = floor($iOnStock);
02348             }
02349         }
02350         if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
02351             $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
02352         }
02353         if ($iOnStock >= $dAmount) {
02354             return true;
02355         } else {
02356             if ($iOnStock > 0) {
02357                 return $iOnStock;
02358             } else {
02359                 $oEx = oxNew('oxArticleInputException');
02360                 $oEx->setMessage('ERROR_MESSAGE_ARTICLE_ARTICLE_NOT_BUYABLE');
02361                 oxRegistry::get("oxUtilsView")->addErrorToDisplay($oEx);
02362 
02363                 return false;
02364             }
02365         }
02366     }
02367 
02368 
02374     public function getLongDescription()
02375     {
02376         if ($this->_oLongDesc === null) {
02377             // initializing
02378             $this->_oLongDesc = new oxField();
02379 
02380 
02381             // choosing which to get..
02382             $sOxid = $this->getId();
02383             $sViewName = getViewName('oxartextends', $this->getLanguage());
02384 
02385             $oDb = oxDb::getDb();
02386             $sDbValue = $oDb->getOne("select oxlongdesc from {$sViewName} where oxid = " . $oDb->quote($sOxid));
02387 
02388             if ($sDbValue != false) {
02389                 $this->_oLongDesc->setValue($sDbValue, oxField::T_RAW);
02390             } elseif ($this->oxarticles__oxparentid->value) {
02391                 if (!$this->isAdmin() || $this->_blLoadParentData) {
02392                     $oParent = $this->getParentArticle();
02393                     if ($oParent) {
02394                         $this->_oLongDesc->setValue($oParent->getLongDescription()->getRawValue(), oxField::T_RAW);
02395                     }
02396                 }
02397             }
02398         }
02399 
02400         return $this->_oLongDesc;
02401     }
02402 
02409     public function getLongDesc()
02410     {
02411         return oxRegistry::get("oxUtilsView")->parseThroughSmarty($this->getLongDescription()->getRawValue(), $this->getId() . $this->getLanguage(), null, true);
02412     }
02413 
02421             public function setArticleLongDesc($sDesc)
02422             {
02423 
02424                 // setting current value
02425                 $this->_oLongDesc = new oxField($sDesc, oxField::T_RAW);
02426                 $this->oxarticles__oxlongdesc = new oxField($sDesc, oxField::T_RAW);
02427             }
02428 
02434     public function getAttributes()
02435     {
02436         if ($this->_oAttributeList === null) {
02437             $this->_oAttributeList = oxNew('oxattributelist');
02438             $this->_oAttributeList->loadAttributes($this->getId(), $this->getParentId());
02439         }
02440 
02441         return $this->_oAttributeList;
02442     }
02443 
02449     public function getAttributesDisplayableInBasket()
02450     {
02451         if ($this->_oAttributeList === null) {
02452             $this->_oAttributeList = oxNew('oxattributelist');
02453             $this->_oAttributeList->loadAttributesDisplayableInBasket($this->getId(), $this->getParentId());
02454         }
02455 
02456         return $this->_oAttributeList;
02457     }
02458 
02459 
02466     public function appendLink($sAddParams, $iLang = null)
02467     {
02468         if ($sAddParams) {
02469             if ($iLang === null) {
02470                 $iLang = $this->getLanguage();
02471             }
02472 
02473             $this->_aSeoAddParams[$iLang] = isset($this->_aSeoAddParams[$iLang]) ? $this->_aSeoAddParams[$iLang] . "&amp;" : "";
02474             $this->_aSeoAddParams[$iLang] .= $sAddParams;
02475         }
02476     }
02477 
02486     public function getBaseSeoLink($iLang, $blMain = false)
02487     {
02489         $oEncoder = oxRegistry::get("oxSeoEncoderArticle");
02490         if (!$blMain) {
02491             return $oEncoder->getArticleUrl($this, $iLang, $this->getLinkType());
02492         }
02493 
02494         return $oEncoder->getArticleMainUrl($this, $iLang);
02495     }
02496 
02505     public function getLink($iLang = null, $blMain = false)
02506     {
02507         if (!oxRegistry::getUtils()->seoIsActive()) {
02508             return $this->getStdLink($iLang);
02509         }
02510 
02511         if ($iLang === null) {
02512             $iLang = $this->getLanguage();
02513         }
02514 
02515         $iLinkType = $this->getLinkType();
02516         if (!isset($this->_aSeoUrls[$iLang][$iLinkType])) {
02517             $this->_aSeoUrls[$iLang][$iLinkType] = $this->getBaseSeoLink($iLang, $blMain);
02518         }
02519 
02520         $sUrl = $this->_aSeoUrls[$iLang][$iLinkType];
02521         if (isset($this->_aSeoAddParams[$iLang])) {
02522             $sUrl .= ((strpos($sUrl . $this->_aSeoAddParams[$iLang], '?') === false) ? '?' : '&amp;') . $this->_aSeoAddParams[$iLang];
02523         }
02524 
02525         return $sUrl;
02526     }
02527 
02536     public function getMainLink($iLang = null)
02537     {
02538         return $this->getLink($iLang, true);
02539     }
02540 
02546     public function setLinkType($iType)
02547     {
02548         // resetting details link, to force new
02549         $this->_sDetailLink = null;
02550 
02551         // setting link type
02552         $this->_iLinkType = (int) $iType;
02553     }
02554 
02560     public function getLinkType()
02561     {
02562         return $this->_iLinkType;
02563     }
02564 
02571     public function appendStdLink($sAddParams, $iLang = null)
02572     {
02573         if ($sAddParams) {
02574             if ($iLang === null) {
02575                 $iLang = $this->getLanguage();
02576             }
02577 
02578             $this->_aStdAddParams[$iLang] = isset($this->_aStdAddParams[$iLang]) ? $this->_aStdAddParams[$iLang] . "&amp;" : "";
02579             $this->_aStdAddParams[$iLang] .= $sAddParams;
02580         }
02581     }
02582 
02592     public function getBaseStdLink($iLang, $blAddId = true, $blFull = true)
02593     {
02594         $sUrl = '';
02595         if ($blFull) {
02596             //always returns shop url, not admin
02597             $sUrl = $this->getConfig()->getShopUrl($iLang, false);
02598         }
02599 
02600         $sUrl .= "index.php?cl=details" . ($blAddId ? "&amp;anid=" . $this->getId() : "");
02601 
02602         return $sUrl . (isset($this->_aStdAddParams[$iLang]) ? "&amp;" . $this->_aStdAddParams[$iLang] : "");
02603     }
02604 
02613     public function getStdLink($iLang = null, $aParams = array())
02614     {
02615         if ($iLang === null) {
02616             $iLang = $this->getLanguage();
02617         }
02618 
02619         if (!isset($this->_aStdUrls[$iLang])) {
02620             $this->_aStdUrls[$iLang] = $this->getBaseStdLink($iLang);
02621         }
02622 
02623         return oxRegistry::get("oxUtilsUrl")->processUrl($this->_aStdUrls[$iLang], true, $aParams, $iLang);
02624     }
02625 
02631     public function getMediaUrls()
02632     {
02633         if ($this->_aMediaUrls === null) {
02634             $this->_aMediaUrls = oxNew("oxlist");
02635             $this->_aMediaUrls->init("oxmediaurl");
02636             $this->_aMediaUrls->getBaseObject()->setLanguage($this->getLanguage());
02637 
02638             $sViewName = getViewName("oxmediaurls", $this->getLanguage());
02639             $sQ = "select * from {$sViewName} where oxobjectid = '" . $this->getId() . "'";
02640             $this->_aMediaUrls->selectString($sQ);
02641         }
02642 
02643         return $this->_aMediaUrls;
02644     }
02645 
02651     public function getDynImageDir()
02652     {
02653         return $this->_sDynImageDir;
02654     }
02655 
02661     public function getDispSelList()
02662     {
02663         if ($this->_aDispSelList === null) {
02664             if ($this->getConfig()->getConfigParam('bl_perfLoadSelectLists') && $this->getConfig()->getConfigParam('bl_perfLoadSelectListsInAList')) {
02665                 $this->_aDispSelList = $this->getSelectLists();
02666             }
02667         }
02668 
02669         return $this->_aDispSelList;
02670     }
02671 
02677     public function getMoreDetailLink()
02678     {
02679         if ($this->_sMoreDetailLink == null) {
02680 
02681             // and assign special article values
02682             $this->_sMoreDetailLink = $this->getConfig()->getShopHomeURL() . 'cl=moredetails';
02683 
02684             // not always it is okey, as not all the time active category is the same as primary article cat.
02685             if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
02686                 $this->_sMoreDetailLink .= '&amp;cnid=' . $sActCat;
02687             }
02688             $this->_sMoreDetailLink .= '&amp;anid=' . $this->getId();
02689             $this->_sMoreDetailLink = $this->_sMoreDetailLink;
02690         }
02691 
02692         return $this->_sMoreDetailLink;
02693     }
02694 
02700     public function getToBasketLink()
02701     {
02702         if ($this->_sToBasketLink == null) {
02703             $myConfig = $this->getConfig();
02704 
02705             if (oxRegistry::getUtils()->isSearchEngine()) {
02706                 $this->_sToBasketLink = $this->getLink();
02707             } else {
02708                 // and assign special article values
02709                 $this->_sToBasketLink = $myConfig->getShopHomeURL();
02710 
02711                 // override some classes as these should never showup
02712                 $sActClass = oxRegistry::getConfig()->getRequestParameter('cl');
02713                 if ($sActClass == 'thankyou') {
02714                     $sActClass = 'basket';
02715                 }
02716                 $this->_sToBasketLink .= 'cl=' . $sActClass;
02717 
02718                 // this is not very correct
02719                 if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
02720                     $this->_sToBasketLink .= '&amp;cnid=' . $sActCat;
02721                 }
02722 
02723                 $this->_sToBasketLink .= '&amp;fnc=tobasket&amp;aid=' . $this->getId() . '&amp;anid=' . $this->getId();
02724 
02725                 if ($sTpl = basename(oxRegistry::getConfig()->getRequestParameter('tpl'))) {
02726                     $this->_sToBasketLink .= '&amp;tpl=' . $sTpl;
02727                 }
02728             }
02729         }
02730 
02731         return $this->_sToBasketLink;
02732     }
02733 
02739     public function getStockStatus()
02740     {
02741         return $this->_iStockStatus;
02742     }
02743 
02749     public function getDeliveryDate()
02750     {
02751         if ($this->oxarticles__oxdelivery->value != '0000-00-00') {
02752             return oxRegistry::get("oxUtilsDate")->formatDBDate($this->oxarticles__oxdelivery->value);
02753         }
02754 
02755         return false;
02756     }
02757 
02765     public function getFTPrice()
02766     {
02767         // module
02768         if ($oPrice = $this->getTPrice()) {
02769             if ($dPrice = $this->_getPriceForView($oPrice)) {
02770                 return oxRegistry::getLang()->formatCurrency($dPrice);
02771             }
02772         }
02773     }
02774 
02782     public function getFPrice()
02783     {
02784         if ($oPrice = $this->getPrice()) {
02785             $dPrice = $this->_getPriceForView($oPrice);
02786 
02787             return oxRegistry::getLang()->formatCurrency($dPrice);
02788         }
02789     }
02790 
02795     public function resetRemindStatus()
02796     {
02797         if ($this->oxarticles__oxremindactive->value == 2 &&
02798             $this->oxarticles__oxremindamount->value <= $this->oxarticles__oxstock->value
02799         ) {
02800             $this->oxarticles__oxremindactive->value = 1;
02801         }
02802     }
02803 
02811     public function getFNetPrice()
02812     {
02813         if ($oPrice = $this->getPrice()) {
02814             return oxRegistry::getLang()->formatCurrency($oPrice->getNettoPrice());
02815         }
02816     }
02817 
02823     public function isParentNotBuyable()
02824     {
02825         return $this->_blNotBuyableParent;
02826     }
02827 
02833     public function isNotBuyable()
02834     {
02835         return $this->_blNotBuyable;
02836     }
02837 
02843     public function setBuyableState($blBuyable = false)
02844     {
02845         $this->_blNotBuyable = !$blBuyable;
02846     }
02847 
02853     public function setSelectlist($aSelList)
02854     {
02855         $this->_aDispSelList = $aSelList;
02856     }
02857 
02865     public function getPictureUrl($iIndex = 1)
02866     {
02867         if ($iIndex) {
02868             $sImgName = false;
02869             if (!$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
02870                 $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
02871             }
02872 
02873             $sSize = $this->getConfig()->getConfigParam('aDetailImageSizes');
02874 
02875             return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
02876         }
02877     }
02878 
02887     public function getIconUrl($iIndex = 0)
02888     {
02889         $sImgName = false;
02890         $sDirname = "product/1/";
02891         if ($iIndex && !$this->_isFieldEmpty("oxarticles__oxpic{$iIndex}")) {
02892             $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
02893             $sDirname = "product/{$iIndex}/";
02894         } elseif (!$this->_isFieldEmpty("oxarticles__oxicon")) {
02895             $sImgName = basename($this->oxarticles__oxicon->value);
02896             $sDirname = "product/icon/";
02897         } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
02898             $sImgName = basename($this->oxarticles__oxpic1->value);
02899         }
02900 
02901         $sSize = $this->getConfig()->getConfigParam('sIconsize');
02902 
02903         $sIconUrl = oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, $iIndex);
02904 
02905         return $sIconUrl;
02906     }
02907 
02915     public function getThumbnailUrl($bSsl = null)
02916     {
02917         $sImgName = false;
02918         $sDirname = "product/1/";
02919         if (!$this->_isFieldEmpty("oxarticles__oxthumb")) {
02920             $sImgName = basename($this->oxarticles__oxthumb->value);
02921             $sDirname = "product/thumb/";
02922         } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
02923             $sImgName = basename($this->oxarticles__oxpic1->value);
02924         }
02925 
02926         $sSize = $this->getConfig()->getConfigParam('sThumbnailsize');
02927 
02928         return oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, 0, $bSsl);
02929     }
02930 
02938     public function getZoomPictureUrl($iIndex = '')
02939     {
02940         $iIndex = (int) $iIndex;
02941         if ($iIndex > 0 && !$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
02942             $sImgName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
02943             $sSize = $this->getConfig()->getConfigParam("sZoomImageSize");
02944 
02945             return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
02946         }
02947     }
02948 
02954     public function applyVats(oxPrice $oPrice)
02955     {
02956         $this->_applyVAT($oPrice, $this->getArticleVat());
02957     }
02958 
02964     public function applyDiscountsForVariant($oPrice)
02965     {
02966         // apply discounts
02967         if (!$this->skipDiscounts()) {
02968             $oDiscountList = oxRegistry::get("oxDiscountList");
02969             $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
02970 
02971             reset($aDiscounts);
02972             foreach ($aDiscounts as $oDiscount) {
02973                 $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
02974             }
02975             $oPrice->calculateDiscount();
02976         }
02977     }
02978 
02984     public function getParentArticle()
02985     {
02986         if (($sParentId = $this->oxarticles__oxparentid->value)) {
02987             $sIndex = $sParentId . "_" . $this->getLanguage();
02988             if (!isset(self::$_aLoadedParents[$sIndex])) {
02989                 self::$_aLoadedParents[$sIndex] = oxNew('oxarticle');
02990                 self::$_aLoadedParents[$sIndex]->_blLoadPrice = false;
02991                 self::$_aLoadedParents[$sIndex]->_blLoadVariants = false;
02992 
02993                 if (!self::$_aLoadedParents[$sIndex]->loadInLang($this->getLanguage(), $sParentId)) {
02994                     //return false in case parent product failed to load
02995                     self::$_aLoadedParents[$sIndex] = false;
02996                 }
02997             }
02998 
02999             return self::$_aLoadedParents[$sIndex];
03000         }
03001     }
03002 
03006     public function updateVariantsRemind()
03007     {
03008         // check if it is parent article
03009         if (!$this->isVariant() && $this->_hasAnyVariant()) {
03010             $oDb = oxDb::getDb();
03011             $sOxId = $oDb->quote($this->getId());
03012             $sOxShopId = $oDb->quote($this->getShopId());
03013             $iRemindActive = $oDb->quote($this->oxarticles__oxremindactive->value);
03014             $sUpdate = "
03015                 update oxarticles
03016                     set oxremindactive = $iRemindActive
03017                     where oxparentid = $sOxId and
03018                           oxshopid = $sOxShopId
03019             ";
03020             $oDb->execute($sUpdate);
03021         }
03022     }
03023 
03030     public function getProductId()
03031     {
03032         return $this->getId();
03033     }
03034 
03040     public function getParentId()
03041     {
03042         return $this->oxarticles__oxparentid->value;
03043     }
03044 
03050     public function isOrderArticle()
03051     {
03052         return false;
03053     }
03054 
03060     public function isVariant()
03061     {
03062         return (bool) (isset($this->oxarticles__oxparentid) ? $this->oxarticles__oxparentid->value : false);
03063     }
03064 
03070     public function isMdVariant()
03071     {
03072         $oMdVariant = oxNew("oxVariantHandler");
03073 
03074         return $oMdVariant->isMdVariant($this);
03075     }
03076 
03084     public function getSqlForPriceCategories($sFields = '')
03085     {
03086         if (!$sFields) {
03087             $sFields = 'oxid';
03088         }
03089         $sSelectWhere = "select $sFields from " . $this->_getObjectViewName('oxcategories') . " where";
03090         $sQuotedPrice = oxDb::getDb()->quote($this->oxarticles__oxprice->value);
03091 
03092         return "$sSelectWhere oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice"
03093                . " union $sSelectWhere oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice"
03094                . " union $sSelectWhere oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice";
03095     }
03096 
03104     public function inPriceCategory($sCatNid)
03105     {
03106         $oDb = oxDb::getDb();
03107 
03108         $sQuotedPrice = $oDb->quote($this->oxarticles__oxprice->value);
03109         $sQuotedCnid = $oDb->quote($sCatNid);
03110 
03111         return (bool) $oDb->getOne(
03112             "select 1 from " . $this->_getObjectViewName('oxcategories') . " where oxid=$sQuotedCnid and"
03113             . "(   (oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice)"
03114             . " or (oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice)"
03115             . " or (oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice)"
03116             . ")"
03117         );
03118     }
03119 
03125     public function getMdVariants()
03126     {
03127         if ($this->_oMdVariants) {
03128             return $this->_oMdVariants;
03129         }
03130 
03131         $oParentArticle = $this->getParentArticle();
03132         if ($oParentArticle) {
03133             $oVariants = $oParentArticle->getVariants();
03134         } else {
03135             $oVariants = $this->getVariants();
03136         }
03137 
03138         $oVariantHandler = oxNew("oxVariantHandler");
03139         $this->_oMdVariants = $oVariantHandler->buildMdVariants($oVariants, $this->getId());
03140 
03141         return $this->_oMdVariants;
03142     }
03143 
03149     public function getMdSubvariants()
03150     {
03151         return $this->getMdVariants()->getMdSubvariants();
03152     }
03153 
03162     public function getPictureFieldValue($sFieldName, $iIndex = null)
03163     {
03164         if ($sFieldName) {
03165             $sFieldName = "oxarticles__" . $sFieldName . $iIndex;
03166 
03167             return $this->$sFieldName->value;
03168         }
03169     }
03170 
03178     public function getMasterZoomPictureUrl($iIndex)
03179     {
03180         $sPicUrl = false;
03181         $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
03182 
03183         if ($sPicName && $sPicName != "nopic.jpg") {
03184             $sPicUrl = $this->getConfig()->getPictureUrl("master/product/" . $iIndex . "/" . $sPicName);
03185             if (!$sPicUrl || basename($sPicUrl) == "nopic.jpg") {
03186                 $sPicUrl = false;
03187             }
03188         }
03189 
03190         return $sPicUrl;
03191     }
03192 
03198     public function getUnitName()
03199     {
03200         if ($this->oxarticles__oxunitname->value) {
03201             return oxRegistry::getLang()->translateString($this->oxarticles__oxunitname->value);
03202         }
03203     }
03204 
03212     public function getArticleFiles($blAddFromParent = false)
03213     {
03214         if ($this->_aArticleFiles === null) {
03215 
03216             $this->_aArticleFiles = false;
03217 
03218             $sQ = "SELECT * FROM `oxfiles` WHERE `oxartid` = '" . $this->getId() . "'";
03219 
03220             if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && $blAddFromParent) {
03221                 $sQ .= " OR `oxartId` = '" . $this->oxarticles__oxparentid->value . "'";
03222             }
03223 
03224             $oArticleFiles = oxNew("oxlist");
03225             $oArticleFiles->init("oxfile");
03226             $oArticleFiles->selectString($sQ);
03227             $this->_aArticleFiles = $oArticleFiles;
03228 
03229         }
03230 
03231         return $this->_aArticleFiles;
03232     }
03233 
03239     public function isDownloadable()
03240     {
03241         return $this->oxarticles__oxisdownloadable->value;
03242     }
03243 
03249     public function hasAmountPrice()
03250     {
03251         if (self::$_blHasAmountPrice === null) {
03252 
03253             self::$_blHasAmountPrice = false;
03254 
03255             $oDb = oxDb::getDb();
03256             $sQ = "SELECT 1 FROM `oxprice2article` LIMIT 1";
03257 
03258             if ($oDb->getOne($sQ)) {
03259                 self::$_blHasAmountPrice = true;
03260             }
03261         }
03262 
03263         return self::$_blHasAmountPrice;
03264     }
03265 
03275     protected function _loadVariantList($blSimple, $blRemoveNotOrderables = true, $blForceCoreTable = null)
03276     {
03277         $oVariants = array();
03278         if (($sId = $this->getId())) {
03279             //do not load me as a parent later
03280             self::$_aLoadedParents[$sId . "_" . $this->getLanguage()] = $this;
03281 
03282             $myConfig = $this->getConfig();
03283 
03284             if (!$this->_blLoadVariants ||
03285                 (!$this->isAdmin() && !$myConfig->getConfigParam('blLoadVariants')) ||
03286                 (!$this->isAdmin() && !$this->oxarticles__oxvarcount->value)
03287             ) {
03288                 return $oVariants;
03289             }
03290 
03291             // cache
03292             $sCacheKey = $blSimple ? "simple" : "full";
03293             if ($blRemoveNotOrderables) {
03294                 if (isset($this->_aVariants[$sCacheKey])) {
03295                     return $this->_aVariants[$sCacheKey];
03296                 } else {
03297                     $this->_aVariants[$sCacheKey] = & $oVariants;
03298                 }
03299             } elseif (!$blRemoveNotOrderables) {
03300                 if (isset($this->_aVariantsWithNotOrderables[$sCacheKey])) {
03301                     return $this->_aVariantsWithNotOrderables[$sCacheKey];
03302                 } else {
03303                     $this->_aVariantsWithNotOrderables[$sCacheKey] = & $oVariants;
03304                 }
03305             }
03306 
03307             if (($this->_blHasVariants = $this->_hasAnyVariant($blForceCoreTable))) {
03308 
03309                 //load simple variants for lists
03310                 if ($blSimple) {
03311                     $oVariants = oxNew('oxsimplevariantlist');
03312                     $oVariants->setParent($this);
03313                 } else {
03314                     //loading variants
03315                     $oVariants = oxNew('oxarticlelist');
03316                     $oVariants->getBaseObject()->modifyCacheKey('_variants');
03317                 }
03318 
03319                 startProfile("selectVariants");
03320                 $blUseCoreTable = (bool) $blForceCoreTable;
03321                 $oBaseObject = $oVariants->getBaseObject();
03322                 $oBaseObject->setLanguage($this->getLanguage());
03323 
03324 
03325                 $sArticleTable = $this->getViewName($blUseCoreTable);
03326 
03327                 $sSelect = "select " . $oBaseObject->getSelectFields($blUseCoreTable) . " from $sArticleTable where " .
03328                            $this->getActiveCheckQuery($blUseCoreTable) .
03329                            $this->getVariantsQuery($blRemoveNotOrderables, $blUseCoreTable) .
03330                            " order by $sArticleTable.oxsort";
03331                 $oVariants->selectString($sSelect);
03332 
03333                 //if this is multidimensional variants, make additional processing
03334                 if ($myConfig->getConfigParam('blUseMultidimensionVariants')) {
03335                     $oMdVariants = oxNew("oxVariantHandler");
03336                     $this->_blHasMdVariants = $oMdVariants->isMdVariant($oVariants->current());
03337                 }
03338                 stopProfile("selectVariants");
03339             }
03340 
03341             //if we have variants then depending on config option the parent may be non buyable
03342             if (!$myConfig->getConfigParam('blVariantParentBuyable') && $this->_blHasVariants) {
03343                 $this->_blNotBuyableParent = true;
03344             }
03345 
03346             //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
03347             if (!$myConfig->getConfigParam('blVariantParentBuyable') && count($oVariants) == 0 && $this->_blHasVariants) {
03348                 $this->_blNotBuyable = true;
03349             }
03350         }
03351 
03352         return $oVariants;
03353     }
03354 
03363     protected function _selectCategoryIds($sSql, $sField)
03364     {
03365         $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
03366         $aResult = $oDb->getAll($sSql);
03367         $aReturn = array();
03368 
03369 
03370         foreach ($aResult as $aValue) {
03371             $aValue = array_change_key_case($aValue, CASE_LOWER);
03372 
03373 
03374             $aReturn[] = $aValue[$sField];
03375         }
03376 
03377         return $aReturn;
03378     }
03379 
03387     protected function _getCategoryIdsSelect($blActCats = false)
03388     {
03389         $sO2CView = $this->_getObjectViewName('oxobject2category');
03390         $sCatView = $this->_getObjectViewName('oxcategories');
03391 
03392         $sArticleIdSql = 'oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getId());
03393         if ($this->getParentId()) {
03394             $sArticleIdSql = '(' . $sArticleIdSql . ' or oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getParentId()) . ')';
03395         }
03396         $sActiveCategorySql = $blActCats ? $this->_getActiveCategorySelectSnippet() : '';
03397 
03398         $sSelect = "select
03399                         oxobject2category.oxcatnid as oxcatnid
03400                      from $sO2CView as oxobject2category
03401                         left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid
03402                     where $sArticleIdSql and oxcategories.oxid is not null and oxcategories.oxactive = 1 $sActiveCategorySql
03403                     order by oxobject2category.oxtime";
03404 
03405         return $sSelect;
03406     }
03407 
03413     protected function _getActiveCategorySelectSnippet()
03414     {
03415         $sCatView = $this->_getObjectViewName('oxcategories');
03416         $sActiveCategorySql = "and oxcategories.oxhidden = 0 and (select count(cats.oxid) from $sCatView as cats where cats.oxrootid = oxcategories.oxrootid and cats.oxleft < oxcategories.oxleft and cats.oxright > oxcategories.oxright and ( cats.oxhidden = 1 or cats.oxactive = 0 ) ) = 0 ";
03417 
03418         return $sActiveCategorySql;
03419     }
03420 
03431     protected function _getSelectCatIds($sOXID, $blActCats = false)
03432     {
03433         $sO2CView = $this->_getObjectViewName('oxobject2category');
03434         $sCatView = $this->_getObjectViewName('oxcategories');
03435         $sSelect = "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
03436         $sSelect .= 'where oxobject2category.oxobjectid=' . oxDb::getDb()->quote($sOXID) . ' and oxcategories.oxid is not null and oxcategories.oxactive = 1 ';
03437         if ($blActCats) {
03438             $sSelect .= "and oxcategories.oxhidden = 0 and (select count(cats.oxid) from $sCatView as cats where cats.oxrootid = oxcategories.oxrootid and cats.oxleft < oxcategories.oxleft and cats.oxright > oxcategories.oxright and ( cats.oxhidden = 1 or cats.oxactive = 0 ) ) = 0 ";
03439         }
03440         $sSelect .= 'order by oxobject2category.oxtime ';
03441 
03442         return $sSelect;
03443     }
03444 
03453     protected function _calculatePrice($oPrice, $dVat = null)
03454     {
03455         // apply VAT only if configuration requires it
03456         if (isset($dVat) || !$this->getConfig()->getConfigParam('bl_perfCalcVatOnlyForBasketOrder')) {
03457             $this->_applyVAT($oPrice, isset($dVat) ? $dVat : $this->getArticleVat());
03458         }
03459 
03460         // apply currency
03461         $this->_applyCurrency($oPrice);
03462         // apply discounts
03463         if (!$this->skipDiscounts()) {
03464             $oDiscountList = oxRegistry::get("oxDiscountList");
03465             $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
03466 
03467             reset($aDiscounts);
03468             foreach ($aDiscounts as $oDiscount) {
03469                 $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
03470             }
03471             $oPrice->calculateDiscount();
03472         }
03473 
03474         return $oPrice;
03475     }
03476 
03484     protected function _hasAnyVariant($blForceCoreTable = null)
03485     {
03486         $blHas = false;
03487         if (($sId = $this->getId())) {
03488             if ($this->oxarticles__oxshopid->value == $this->getConfig()->getShopId()) {
03489                 $blHas = (bool) $this->oxarticles__oxvarcount->value;
03490             } else {
03491                 $sArticleTable = $this->getViewName($blForceCoreTable);
03492                 $blHas = (bool) oxDb::getDb()->getOne("select 1 from $sArticleTable where oxparentid='{$sId}'");
03493             }
03494         }
03495 
03496         return $blHas;
03497     }
03498 
03504     protected function _isStockStatusChanged()
03505     {
03506         return $this->_iStockStatus != $this->_iStockStatusOnLoad;
03507     }
03508 
03514     protected function _isVisibilityChanged()
03515     {
03516         return $this->_isStockStatusChanged() && ($this->_iStockStatus == -1 || $this->_iStockStatusOnLoad == -1);
03517     }
03518 
03524     protected function _saveArtLongDesc()
03525     {
03526         $myConfig = $this->getConfig();
03527         $sShopId = $myConfig->getShopID();
03528         if (in_array("oxlongdesc", $this->_aSkipSaveFields)) {
03529             return;
03530         }
03531 
03532         if ($this->_blEmployMultilanguage) {
03533             $sValue = $this->getLongDescription()->getRawValue();
03534             if ($sValue !== null) {
03535                 $oArtExt = oxNew('oxI18n');
03536                 $oArtExt->init('oxartextends');
03537                 $oArtExt->setLanguage((int) $this->getLanguage());
03538                 if (!$oArtExt->load($this->getId())) {
03539                     $oArtExt->setId($this->getId());
03540                 }
03541                 $oArtExt->oxartextends__oxlongdesc = new oxField($sValue, oxField::T_RAW);
03542                 $oArtExt->save();
03543             }
03544         } else {
03545             $oArtExt = oxNew('oxI18n');
03546             $oArtExt->setEnableMultilang(false);
03547             $oArtExt->init('oxartextends');
03548             $aObjFields = $oArtExt->_getAllFields(true);
03549             if (!$oArtExt->load($this->getId())) {
03550                 $oArtExt->setId($this->getId());
03551             }
03552 
03553             foreach ($aObjFields as $sKey => $sValue) {
03554                 if (preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey)) {
03555                     $sField = $this->_getFieldLongName($sKey);
03556 
03557                     if (isset($this->$sField)) {
03558                         $sLongDesc = null;
03559                         if ($this->$sField instanceof oxField) {
03560                             $sLongDesc = $this->$sField->getRawValue();
03561                         } elseif (is_object($this->$sField)) {
03562                             $sLongDesc = $this->$sField->value;
03563                         }
03564                         if (isset($sLongDesc)) {
03565                             $sAEField = $oArtExt->_getFieldLongName($sKey);
03566                             $oArtExt->$sAEField = new oxField($sLongDesc, oxField::T_RAW);
03567                         }
03568                     }
03569                 }
03570             }
03571             $oArtExt->save();
03572         }
03573     }
03574 
03578     protected function _skipSaveFields()
03579     {
03580         $myConfig = $this->getConfig();
03581 
03582         $this->_aSkipSaveFields = array();
03583 
03584         $this->_aSkipSaveFields[] = 'oxtimestamp';
03585         // $this->_aSkipSaveFields[] = 'oxlongdesc';
03586         $this->_aSkipSaveFields[] = 'oxinsert';
03587         $this->_addSkippedSaveFieldsForMapping();
03588 
03589         if (!$this->_blAllowEmptyParentId && (!isset($this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '')) {
03590             $this->_aSkipSaveFields[] = 'oxparentid';
03591         }
03592 
03593     }
03594 
03604     protected function _mergeDiscounts($aDiscounts, $aItemDiscounts)
03605     {
03606         foreach ($aItemDiscounts as $sKey => $oDiscount) {
03607             // add prices of the same discounts
03608             if (array_key_exists($sKey, $aDiscounts)) {
03609                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
03610             } else {
03611                 $aDiscounts[$sKey] = $oDiscount;
03612             }
03613         }
03614 
03615         return $aDiscounts;
03616     }
03617 
03623     protected function _getGroupPrice()
03624     {
03625         $sPriceSufix = $this->_getUserPriceSufix();
03626         $sVarName = "oxarticles__oxprice{$sPriceSufix}";
03627         $dPrice = $this->$sVarName->value;
03628 
03629         // #1437/1436C - added config option, and check for zero A,B,C price values
03630         if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices') && (double) $dPrice == 0) {
03631             $dPrice = $this->oxarticles__oxprice->value;
03632         }
03633 
03634         return $dPrice;
03635     }
03636 
03645     protected function _getAmountPrice($dAmount = 1)
03646     {
03647         startProfile("_getAmountPrice");
03648 
03649         $dPrice = $this->_getGroupPrice();
03650         $oAmtPrices = $this->_getAmountPriceList();
03651         foreach ($oAmtPrices as $oAmPrice) {
03652             if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
03653                 && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
03654                 && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value
03655             ) {
03656                 $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
03657             }
03658         }
03659 
03660         stopProfile("_getAmountPrice");
03661 
03662         return $dPrice;
03663     }
03664 
03673     protected function _modifySelectListPrice($dPrice, $aChosenList = null)
03674     {
03675         $myConfig = $this->getConfig();
03676         // #690
03677         if ($myConfig->getConfigParam('bl_perfLoadSelectLists') && $myConfig->getConfigParam('bl_perfUseSelectlistPrice')) {
03678 
03679             $aSelLists = $this->getSelectLists();
03680 
03681             foreach ($aSelLists as $key => $aSel) {
03682                 if (isset($aChosenList[$key]) && isset($aSel[$aChosenList[$key]])) {
03683                     $oSel = $aSel[$aChosenList[$key]];
03684                     if ($oSel->priceUnit == 'abs') {
03685                         $dPrice += $oSel->price;
03686                     } elseif ($oSel->priceUnit == '%') {
03687                         $dPrice += oxPrice::percent($dPrice, $oSel->price);
03688                     }
03689                 }
03690             }
03691         }
03692 
03693         return $dPrice;
03694     }
03695 
03703     protected function _fillAmountPriceList($aAmPriceList)
03704     {
03705         $oLang = oxRegistry::getLang();
03706 
03707         // trying to find lowest price value
03708         foreach ($aAmPriceList as $sId => $oItem) {
03709 
03710             $oItemPrice = $this->_getPriceObject();
03711             if ($oItem->oxprice2article__oxaddabs->value) {
03712 
03713                 $dBasePrice = $oItem->oxprice2article__oxaddabs->value;
03714                 $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
03715 
03716                 $oItemPrice->setPrice($dBasePrice);
03717                 $this->_calculatePrice($oItemPrice);
03718 
03719             } else {
03720                 $dBasePrice = $this->_getGroupPrice();
03721                 $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
03722                 $oItemPrice->setPrice($dBasePrice);
03723                 $oItemPrice->subtractPercent($oItem->oxprice2article__oxaddperc->value);
03724             }
03725 
03726 
03727             $aAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency($this->_getPriceForView($oItemPrice));
03728         }
03729 
03730         return $aAmPriceList;
03731     }
03732 
03740     public function getVariantIds($blActiveVariants = true)
03741     {
03742         $aSelect = array();
03743         $sId = $this->getId();
03744         if ($sId) {
03745             $sActiveSqlSnippet = "";
03746             if ($blActiveVariants) {
03747                 $sActiveSqlSnippet = " and " . $this->getSqlActiveSnippet(true);
03748             }
03749             $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
03750             $sQ = "select oxid from " . $this->getViewName(true) . " where oxparentid = " . $oDb->quote($sId) .
03751                   $sActiveSqlSnippet . " order by oxsort";
03752             $oRs = $oDb->select($sQ);
03753             if ($oRs != false && $oRs->recordCount() > 0) {
03754                 while (!$oRs->EOF) {
03755                     $aSelect[] = reset($oRs->fields);
03756                     $oRs->moveNext();
03757                 }
03758             }
03759         }
03760 
03761         return $aSelect;
03762     }
03763 
03773     protected function _getVariantsIds($blActiveVariants = true)
03774     {
03775         return $this->getVariantIds($blActiveVariants);
03776     }
03777 
03783     public function getArticleVat()
03784     {
03785         if (!isset($this->_dArticleVat)) {
03786             $this->_dArticleVat = oxRegistry::get("oxVatSelector")->getArticleVat($this);
03787         }
03788 
03789         return $this->_dArticleVat;
03790     }
03791 
03798     protected function _applyVAT(oxPrice $oPrice, $dVat)
03799     {
03800         startProfile(__FUNCTION__);
03801         $oPrice->setVAT($dVat);
03803         $oVatSelector = oxRegistry::get("oxVatSelector");
03804         if (($dVat = $oVatSelector->getArticleUserVat($this)) !== false) {
03805             $oPrice->setUserVat($dVat);
03806         }
03807         stopProfile(__FUNCTION__);
03808     }
03809 
03816     protected function _applyCurrency(oxPrice $oPrice, $oCur = null)
03817     {
03818         if (!$oCur) {
03819             $oCur = $this->getConfig()->getActShopCurrencyObject();
03820         }
03821 
03822         $oPrice->multiply($oCur->rate);
03823     }
03824 
03825 
03832     protected function _getAttribsString(&$sAttributeSql, &$iCnt)
03833     {
03834         // we do not use lists here as we don't need this overhead right now
03835         $oDb = oxDb::getDb();
03836         $sSelect = 'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid=' . $oDb->quote($this->getId());
03837         if ($this->getParentId()) {
03838             $sSelect .= ' OR oxobject2attribute.oxobjectid=' . $oDb->quote($this->getParentId());
03839         }
03840         $sAttributeSql = '';
03841         $aAttributeIds = $oDb->getCol($sSelect);
03842         if (is_array($aAttributeIds) && count($aAttributeIds)) {
03843             $aAttributeIds = array_unique($aAttributeIds);
03844             $iCnt = count($aAttributeIds);
03845             $sAttributeSql .= 't1.oxattrid IN ( ' . implode(',', $oDb->quoteArray($aAttributeIds)) . ') ';
03846         }
03847     }
03848 
03857     protected function _getSimList($sAttributeSql, $iCnt)
03858     {
03859         // #523A
03860         $iAttrPercent = $this->getConfig()->getConfigParam('iAttributesPercent') / 100;
03861         // 70% same attributes
03862         if (!$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
03863             $iAttrPercent = 0.70;
03864         }
03865         // #1137V iAttributesPercent = 100 doesn't work
03866         $iHitMin = ceil($iCnt * $iAttrPercent);
03867 
03868         $aExcludeIds = array();
03869         $aExcludeIds[] = $this->getId();
03870         if ($this->getParentId()) {
03871             $aExcludeIds[] = $this->getParentId();
03872         }
03873 
03874         // we do not use lists here as we don't need this overhead right now
03875         $sSelect = "select oxobjectid from oxobject2attribute as t1 where
03876                     ( $sAttributeSql )
03877                     and t1.oxobjectid NOT IN (" . implode(', ', oxDb::getDb()->quoteArray($aExcludeIds)) . ")
03878                     group by t1.oxobjectid having count(*) >= $iHitMin LIMIT 0, 20";
03879 
03880         return oxDb::getDb()->getCol($sSelect);
03881     }
03882 
03891     protected function _generateSimListSearchStr($sArticleTable, $aList)
03892     {
03893         $sFieldList = $this->getSelectFields();
03894         $aList = array_slice($aList, 0, $this->getConfig()->getConfigParam('iNrofSimilarArticles'));
03895 
03896         $sSearch = "select $sFieldList from $sArticleTable where " . $this->getSqlActiveSnippet() . "  and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
03897 
03898         $sSearch .= implode(',', oxdb::getDb()->quoteArray($aList)) . ')';
03899 
03900         // #524A -- randomizing articles in attribute list
03901         $sSearch .= ' order by rand() ';
03902 
03903         return $sSearch;
03904     }
03905 
03914     protected function _generateSearchStr($sOXID, $blSearchPriceCat = false)
03915     {
03916 
03917         $sCatView = getViewName('oxcategories', $this->getLanguage());
03918         $sO2CView = getViewName('oxobject2category');
03919 
03920         // we do not use lists here as we don't need this overhead right now
03921         if (!$blSearchPriceCat) {
03922             $sSelect = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
03923                          {$sCatView}.oxid = oxobject2category.oxcatnid
03924                          where oxobject2category.oxobjectid=" . oxDb::getDb()->quote($sOXID) . " and {$sCatView}.oxid is not null ";
03925         } else {
03926             $sSelect = "select {$sCatView}.* from {$sCatView} where
03927                          '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
03928                          '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
03929         }
03930 
03931         return $sSelect;
03932     }
03933 
03939     protected function _generateSearchStrForCustomerBought()
03940     {
03941         $sArtTable = $this->getViewName();
03942         $sOrderArtTable = getViewName('oxorderarticles');
03943 
03944         // fetching filter params
03945         $sIn = " '{$this->oxarticles__oxid->value}' ";
03946         if ($this->oxarticles__oxparentid->value) {
03947 
03948             // adding article parent
03949             $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
03950             $sParentIdForVariants = $this->oxarticles__oxparentid->value;
03951 
03952         } else {
03953             $sParentIdForVariants = $this->getId();
03954         }
03955 
03956         // adding variants
03957         $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
03958         $oRs = $oDb->select("select oxid from {$sArtTable} where oxparentid = " . $oDb->quote($sParentIdForVariants) . " and oxid != " . $oDb->quote($this->oxarticles__oxid->value));
03959         if ($oRs != false && $oRs->recordCount() > 0) {
03960             while (!$oRs->EOF) {
03961                 $sIn .= ", " . $oDb->quote(current($oRs->fields)) . " ";
03962                 $oRs->moveNext();
03963             }
03964         }
03965 
03966         $iLimit = (int) $this->getConfig()->getConfigParam('iNrofCustomerWhoArticles');
03967         $iLimit = $iLimit ? ($iLimit * 10) : 50;
03968 
03969         // building sql (optimized)
03970         $sQ = "select distinct {$sArtTable}.* from (
03971                    select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
03972                ) as suborder
03973                left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
03974                left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
03975                where {$sArtTable}.oxid not in ( {$sIn} )
03976                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and " . $this->getSqlActiveSnippet();
03977 
03978         /* non optimized, but could be used if index forcing is not supported
03979         // building sql
03980         $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
03981                    select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
03982                ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
03983                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
03984                and ".$this->getSqlActiveSnippet();
03985         */
03986 
03987         return $sQ;
03988     }
03989 
03999     protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
04000     {
04001         $sCategoryView = getViewName('oxcategories');
04002         $sO2CView = getViewName('oxobject2category');
04003 
04004         $oDb = oxDb::getDb();
04005         $sOXID = $oDb->quote($sOXID);
04006         $sCatId = $oDb->quote($sCatId);
04007 
04008         if (!$dPriceFromTo) {
04009             $sSelect = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
04010             $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
04011             $sSelect .= "where oxobject2category.oxcatnid=$sCatId and oxobject2category.oxobjectid=$sOXID ";
04012             $sSelect .= "and oxcategories.oxactive = 1 order by oxobject2category.oxtime ";
04013         } else {
04014             $dPriceFromTo = $oDb->quote($dPriceFromTo);
04015             $sSelect = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
04016             $sSelect .= "oxcategories.oxid=$sCatId and $dPriceFromTo >= oxcategories.oxpricefrom and ";
04017             $sSelect .= "$dPriceFromTo <= oxcategories.oxpriceto ";
04018         }
04019 
04020         return $sSelect;
04021     }
04022 
04028     protected function _getAmountPriceList()
04029     {
04030         if ($this->_oAmountPriceList === null) {
04031             $oAmPriceList = oxNew('oxAmountPricelist');
04032 
04033             if (!$this->skipDiscounts()) {
04034                 //collecting assigned to article amount-price list
04035                 $oAmPriceList->load($this);
04036 
04037                 // prepare abs prices if currently having percentages
04038                 $oBasePrice = $this->_getGroupPrice();
04039                 foreach ($oAmPriceList as $oAmPrice) {
04040                     if ($oAmPrice->oxprice2article__oxaddperc->value) {
04041                         $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent($oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value), oxField::T_RAW);
04042                     }
04043                 }
04044 
04045             }
04046 
04047             $this->_oAmountPriceList = $oAmPriceList;
04048         }
04049 
04050         return $this->_oAmountPriceList;
04051     }
04052 
04060     protected function _isFieldEmpty($sFieldName)
04061     {
04062         $mValue = $this->$sFieldName->value;
04063 
04064         if (is_null($mValue)) {
04065             return true;
04066         }
04067 
04068         if ($mValue === '') {
04069             return true;
04070         }
04071 
04072         // certain fields with zero value treat as empty
04073         $aZeroValueFields = array('oxarticles__oxprice', 'oxarticles__oxvat', 'oxarticles__oxunitquantity');
04074 
04075         if (!$mValue && in_array($sFieldName, $aZeroValueFields)) {
04076             return true;
04077         }
04078 
04079 
04080         if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
04081             return true;
04082         }
04083 
04084         $sFieldName = strtolower($sFieldName);
04085 
04086         if ($sFieldName == 'oxarticles__oxicon' && (strpos($mValue, "nopic_ico.jpg") !== false || strpos($mValue, "nopic.jpg") !== false)) {
04087             return true;
04088         }
04089 
04090         if (strpos($mValue, "nopic.jpg") !== false && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom')) {
04091             return true;
04092         }
04093 
04094         return false;
04095     }
04096 
04104     protected function _assignParentFieldValue($sFieldName)
04105     {
04106         if (!($oParentArticle = $this->getParentArticle())) {
04107             return;
04108         }
04109 
04110         $sCopyFieldName = $this->_getFieldLongName($sFieldName);
04111 
04112         // assigning only these which parent article has
04113         if ($oParentArticle->$sCopyFieldName != null) {
04114 
04115             // only overwrite database values
04116             if (substr($sCopyFieldName, 0, 12) != 'oxarticles__') {
04117                 return;
04118             }
04119 
04120             //do not copy certain fields
04121             if (in_array($sCopyFieldName, $this->_aNonCopyParentFields)) {
04122                 return;
04123             }
04124 
04125             //skip picture parent value assignment in case master image is set for variant
04126             if ($this->_isFieldEmpty($sCopyFieldName) && $this->_isImageField($sCopyFieldName) && $this->_hasMasterImage(1)) {
04127                 return;
04128             }
04129 
04130             //COPY THE VALUE
04131             if ($this->_isFieldEmpty($sCopyFieldName)) {
04132                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
04133             }
04134         }
04135     }
04136 
04144     protected function _isImageField($sFieldName)
04145     {
04146         $blIsImageField = (stristr($sFieldName, '_oxthumb') || stristr($sFieldName, '_oxicon') || stristr($sFieldName, '_oxzoom') || stristr($sFieldName, '_oxpic'));
04147 
04148         return $blIsImageField;
04149     }
04150 
04154     protected function _assignParentFieldValues()
04155     {
04156         startProfile('articleAssignParentInternal');
04157         if ($this->oxarticles__oxparentid->value) {
04158             // yes, we are in fact a variant
04159             if (!$this->isAdmin() || ($this->_blLoadParentData && $this->isAdmin())) {
04160                 foreach ($this->_aFieldNames as $sFieldName => $sVal) {
04161                     $this->_assignParentFieldValue($sFieldName);
04162                 }
04163             }
04164         }
04165         stopProfile('articleAssignParentInternal');
04166     }
04167 
04171     protected function _assignNotBuyableParent()
04172     {
04173         if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') &&
04174             ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value)
04175         ) {
04176             $this->_blNotBuyableParent = true;
04177 
04178         }
04179     }
04180 
04184     protected function _assignStock()
04185     {
04186         $myConfig = $this->getConfig();
04187         // -----------------------------------
04188         // stock
04189         // -----------------------------------
04190 
04191         // #1125 A. must round (using floor()) value taken from database and cast to int
04192         if (!$myConfig->getConfigParam('blAllowUnevenAmounts') && !$this->isAdmin()) {
04193             $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
04194         }
04195         //GREEN light
04196         $this->_iStockStatus = 0;
04197 
04198         // if we have flag /*1 or*/ 4 - we show always green light
04199         if ($myConfig->getConfigParam('blUseStock') && /*$this->oxarticles__oxstockflag->value != 1 && */
04200             $this->oxarticles__oxstockflag->value != 4
04201         ) {
04202             //ORANGE light
04203             $iStock = $this->oxarticles__oxstock->value;
04204 
04205             if ($this->_blNotBuyableParent) {
04206                 $iStock = $this->oxarticles__oxvarstock->value;
04207             }
04208 
04209 
04210             if ($iStock <= $myConfig->getConfigParam('sStockWarningLimit') && $iStock > 0) {
04211                 $this->_iStockStatus = 1;
04212             }
04213 
04214             //RED light
04215             if ($iStock <= 0) {
04216                 $this->_iStockStatus = -1;
04217             }
04218         }
04219 
04220 
04221         // stock
04222         if ($myConfig->getConfigParam('blUseStock') && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
04223             $iOnStock = $this->oxarticles__oxstock->value;
04224             if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
04225                 $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
04226             }
04227             if ($iOnStock <= 0) {
04228                 $this->setBuyableState(false);
04229             }
04230         }
04231 
04232         //exceptional handling for variant parent stock:
04233         if ($this->_blNotBuyable && $this->oxarticles__oxvarstock->value) {
04234             $this->setBuyableState(true);
04235             //but then at least setting notBuaybleParent to true
04236             $this->_blNotBuyableParent = true;
04237         }
04238 
04239         //special treatment for lists when blVariantParentBuyable config option is set to false
04240         //then we just hide "to basket" button.
04241         //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
04242         if (!$myConfig->getConfigParam('blVariantParentBuyable') && !$myConfig->getConfigParam('blLoadVariants') && $this->oxarticles__oxvarstock->value) {
04243             $this->setBuyableState(false);
04244         }
04245 
04246         //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
04247         if (!$this->_blNotBuyable && $this->_blNotBuyableParent && $this->oxarticles__oxvarcount->value == 0) {
04248             $this->setBuyableState(false);
04249         }
04250     }
04251 
04255     protected function _assignPersistentParam()
04256     {
04257         // Persistent Parameter Handling
04258         $aPersParam = oxRegistry::getSession()->getVariable('persparam');
04259         if (isset($aPersParam) && isset($aPersParam[$this->getId()])) {
04260             $this->_aPersistParam = $aPersParam[$this->getId()];
04261         }
04262     }
04263 
04267     protected function _assignDynImageDir()
04268     {
04269         $myConfig = $this->getConfig();
04270 
04271         $sThisShop = $this->oxarticles__oxshopid->value;
04272 
04273         $this->_sDynImageDir = $myConfig->getPictureUrl(null, false);
04274         $this->dabsimagedir = $myConfig->getPictureDir(false); //$sThisShop
04275         $this->nossl_dimagedir = $myConfig->getPictureUrl(null, false, false, null, $sThisShop); //$sThisShop
04276         $this->ssl_dimagedir = $myConfig->getPictureUrl(null, false, true, null, $sThisShop); //$sThisShop
04277     }
04278 
04282     protected function _assignComparisonListFlag()
04283     {
04284         // #657 add a flag if article is on comparisonlist
04285 
04286         $aItems = oxRegistry::getSession()->getVariable('aFiltcompproducts');
04287         if (isset($aItems[$this->getId()])) {
04288             $this->_blIsOnComparisonList = true;
04289         }
04290     }
04291 
04299     protected function _insert()
04300     {
04301         // set oxinsert
04302         $sNow = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
04303         $this->oxarticles__oxinsert = new oxField($sNow);
04304         if (!is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
04305             $this->oxarticles__oxsubclass = new oxField('oxarticle');
04306         }
04307 
04308         $blRes = parent::_insert();
04309 
04310 
04311         return $blRes;
04312     }
04313 
04319     protected function _update()
04320     {
04321 
04322         $this->setUpdateSeo(true);
04323         $this->_setUpdateSeoOnFieldChange('oxtitle');
04324 
04325         $this->_skipSaveFields();
04326 
04327         $myConfig = $this->getConfig();
04328 
04329 
04330         $blRes = parent::_update();
04331 
04332 
04333         return $blRes;
04334     }
04335 
04343     protected function _deleteRecords($sOXID)
04344     {
04345         $oDb = oxDb::getDb();
04346 
04347         $sOXID = $oDb->quote($sOXID);
04348 
04349         //remove other records
04350         $sDelete = 'delete from oxobject2article where oxarticlenid = ' . $sOXID . ' or oxobjectid = ' . $sOXID . ' ';
04351         $oDb->execute($sDelete);
04352 
04353         $sDelete = 'delete from oxobject2attribute where oxobjectid = ' . $sOXID . ' ';
04354         $oDb->execute($sDelete);
04355 
04356         $sDelete = 'delete from oxobject2category where oxobjectid = ' . $sOXID . ' ';
04357         $oDb->execute($sDelete);
04358 
04359         $sDelete = 'delete from oxobject2selectlist where oxobjectid = ' . $sOXID . ' ';
04360         $oDb->execute($sDelete);
04361 
04362         $sDelete = 'delete from oxprice2article where oxartid = ' . $sOXID . ' ';
04363         $oDb->execute($sDelete);
04364 
04365         $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = ' . $sOXID . ' ';
04366         $oDb->execute($sDelete);
04367 
04368         $sDelete = 'delete from oxratings where oxobjectid = ' . $sOXID . ' ';
04369         $rs = $oDb->execute($sDelete);
04370 
04371         $sDelete = 'delete from oxaccessoire2article where oxobjectid = ' . $sOXID . ' or oxarticlenid = ' . $sOXID . ' ';
04372         $oDb->execute($sDelete);
04373 
04374         //#1508C - deleting oxobject2delivery entries added
04375         $sDelete = 'delete from oxobject2delivery where oxobjectid = ' . $sOXID . ' and oxtype=\'oxarticles\' ';
04376         $oDb->execute($sDelete);
04377 
04378         $sDelete = 'delete from oxartextends where oxid = ' . $sOXID . ' ';
04379         $oDb->execute($sDelete);
04380 
04381         //delete the record
04382         foreach ($this->_getLanguageSetTables("oxartextends") as $sSetTbl) {
04383             $oDb->execute("delete from $sSetTbl where oxid = {$sOXID}");
04384         }
04385 
04386         $sDelete = 'delete from oxactions2article where oxartid = ' . $sOXID . ' ';
04387         $rs = $oDb->execute($sDelete);
04388 
04389         $sDelete = 'delete from oxobject2list where oxobjectid = ' . $sOXID . ' ';
04390         $rs = $oDb->execute($sDelete);
04391 
04392 
04393         return $rs;
04394     }
04395 
04401     protected function _deleteVariantRecords($sOXID)
04402     {
04403         if ($sOXID) {
04404             $oDb = oxDb::getDb();
04405             //collect variants to remove recursively
04406             $sQ = 'select oxid from ' . $this->getViewName() . ' where oxparentid = ' . $oDb->quote($sOXID);
04407             $rs = $oDb->select($sQ, false, false);
04408             $oArticle = oxNew("oxArticle");
04409             if ($rs != false && $rs->recordCount() > 0) {
04410                 while (!$rs->EOF) {
04411                     $oArticle->setId($rs->fields[0]);
04412                     $oArticle->delete();
04413                     $rs->moveNext();
04414                 }
04415             }
04416         }
04417     }
04418 
04422     protected function _deletePics()
04423     {
04424         $myUtilsPic = oxRegistry::get("oxUtilsPic");
04425         $myConfig = $this->getConfig();
04426         $oPictureHandler = oxRegistry::get("oxPictureHandler");
04427 
04428         //deleting custom main icon
04429         $oPictureHandler->deleteMainIcon($this);
04430 
04431         //deleting custom thumbnail
04432         $oPictureHandler->deleteThumbnail($this);
04433 
04434         $sAbsDynImageDir = $myConfig->getPictureDir(false);
04435 
04436         // deleting master image and all generated images
04437         $iPicCount = $myConfig->getConfigParam('iPicCount');
04438         for ($i = 1; $i <= $iPicCount; $i++) {
04439             $oPictureHandler->deleteArticleMasterPicture($this, $i);
04440         }
04441     }
04442 
04450     protected function _onChangeResetCounts($sOxid, $sVendorId = null, $sManufacturerId = null)
04451     {
04452         $myUtilsCount = oxRegistry::get("oxUtilsCount");
04453 
04454         if ($sVendorId) {
04455             $myUtilsCount->resetVendorArticleCount($sVendorId);
04456         }
04457 
04458         if ($sManufacturerId) {
04459             $myUtilsCount->resetManufacturerArticleCount($sManufacturerId);
04460         }
04461 
04462         $aCategoryIds = $this->getCategoryIds();
04463         //also reseting category counts
04464         foreach ($aCategoryIds as $sCatId) {
04465             $myUtilsCount->resetCatArticleCount($sCatId, false);
04466         }
04467     }
04468 
04474     protected function _onChangeUpdateStock($sParentID)
04475     {
04476         if ($sParentID) {
04477             $oDb = oxDb::getDb();
04478             $sParentIdQuoted = $oDb->quote($sParentID);
04479             $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = ' . $sParentIdQuoted;
04480             $rs = $oDb->select($sQ, false, false);
04481             $iOldStock = $rs->fields[0];
04482             $iVendorID = $rs->fields[1];
04483             $iManufacturerID = $rs->fields[2];
04484 
04485             $sQ = 'select sum(oxstock) from ' . $this->getViewName(true) . ' where oxparentid = ' . $sParentIdQuoted . ' and ' . $this->getSqlActiveSnippet(true) . ' and oxstock > 0 ';
04486             $iStock = (float) $oDb->getOne($sQ, false, false);
04487 
04488             $sQ = 'update oxarticles set oxvarstock = ' . $iStock . ' where oxid = ' . $sParentIdQuoted;
04489             $oDb->execute($sQ);
04490 
04491             //now lets update category counts
04492             //first detect stock status change for this article (to or from 0)
04493             if ($iStock < 0) {
04494                 $iStock = 0;
04495             }
04496             if ($iOldStock < 0) {
04497                 $iOldStock = 0;
04498             }
04499             if ($this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock) {
04500                 //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
04501                 // so far we leave it like this but later we could move all count resets to one or two functions
04502                 $this->_onChangeResetCounts($sParentID, $iVendorID, $iManufacturerID);
04503             }
04504         }
04505     }
04506 
04512     protected function _onChangeStockResetCount($sOxid)
04513     {
04514         $myConfig = $this->getConfig();
04515 
04516         if ($myConfig->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2 &&
04517             ($this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value) <= 0
04518         ) {
04519 
04520             $this->_onChangeResetCounts($sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
04521         }
04522     }
04523 
04529     protected function _onChangeUpdateVarCount($sParentID)
04530     {
04531         if ($sParentID) {
04532             $oDb = oxDb::getDb();
04533             $sParentIdQuoted = $oDb->quote($sParentID);
04534             $sQ = "select count(*) as varcount from oxarticles where oxparentid = {$sParentIdQuoted}";
04535             $iVarCount = (int) $oDb->getOne($sQ, false, false);
04536 
04537             $sQ = "update oxarticles set oxvarcount = {$iVarCount} where oxid = {$sParentIdQuoted}";
04538             $oDb->execute($sQ);
04539         }
04540     }
04541 
04547     protected function _setVarMinMaxPrice($sParentId)
04548     {
04549         if ($sParentId) {
04550             $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
04551             $sQ = '
04552                 SELECT
04553                     MIN( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varminprice`,
04554                     MAX( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varmaxprice`
04555                 FROM ' . $this->getViewName(true) . ' AS `oxarticles`
04556                     LEFT JOIN ' . $this->getViewName(true) . ' AS `p` ON ( `p`.`oxid` = `oxarticles`.`oxparentid` AND `p`.`oxprice` > 0 )
04557                 WHERE ' . $this->getSqlActiveSnippet(true) . '
04558                     AND ( `oxarticles`.`oxparentid` = ' . $oDb->quote($sParentId) . ' )';
04559             $oDb->setFetchMode(oxDb::FETCH_MODE_ASSOC);
04560             $aPrices = $oDb->getRow($sQ, false, false);
04561             if (!is_null($aPrices['varminprice']) || !is_null($aPrices['varmaxprice'])) {
04562                 $sQ = '
04563                     UPDATE `oxarticles`
04564                     SET
04565                         `oxvarminprice` = ' . $oDb->quote($aPrices['varminprice']) . ',
04566                         `oxvarmaxprice` = ' . $oDb->quote($aPrices['varmaxprice']) . '
04567                     WHERE
04568                         `oxid` = ' . $oDb->quote($sParentId);
04569             } else {
04570                 $sQ = '
04571                     UPDATE `oxarticles`
04572                     SET
04573                         `oxvarminprice` = `oxprice`,
04574                         `oxvarmaxprice` = `oxprice`
04575                     WHERE
04576                         `oxid` = ' . $oDb->quote($sParentId);
04577             }
04578             $oDb->execute($sQ);
04579         }
04580     }
04581 
04589     protected function _hasMasterImage($iIndex)
04590     {
04591         $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
04592 
04593         if ($sPicName == "nopic.jpg" || $sPicName == "") {
04594             return false;
04595         }
04596         if ($this->isVariant() &&
04597             $this->getParentArticle() &&
04598             $this->getParentArticle()->{"oxarticles__oxpic" . $iIndex}->value == $this->{"oxarticles__oxpic" . $iIndex}->value
04599         ) {
04600             return false;
04601         }
04602 
04603         $sMasterPic = 'product/' . $iIndex . "/" . $sPicName;
04604 
04605         if ($this->getConfig()->getMasterPicturePath($sMasterPic)) {
04606             return true;
04607         }
04608 
04609         return false;
04610     }
04611 
04617     protected function _isPriceViewModeNetto()
04618     {
04619         $blResult = (bool) $this->getConfig()->getConfigParam('blShowNetPrice');
04620         $oUser = $this->getArticleUser();
04621         if ($oUser) {
04622             $blResult = $oUser->isPriceViewModeNetto();
04623         }
04624 
04625         return $blResult;
04626     }
04627 
04628 
04636     protected function _getPriceObject($blCalculationModeNetto = null)
04637     {
04638         $oPrice = oxNew('oxPrice');
04639 
04640         if ($blCalculationModeNetto === null) {
04641             $blCalculationModeNetto = $this->_isPriceViewModeNetto();
04642         }
04643 
04644         if ($blCalculationModeNetto) {
04645             $oPrice->setNettoPriceMode();
04646         } else {
04647             $oPrice->setBruttoPriceMode();
04648         }
04649 
04650         return $oPrice;
04651     }
04652 
04653 
04661     protected function _getPriceForView($oPrice)
04662     {
04663         if ($this->_isPriceViewModeNetto()) {
04664             $dPrice = $oPrice->getNettoPrice();
04665         } else {
04666             $dPrice = $oPrice->getBruttoPrice();
04667         }
04668 
04669         return $dPrice;
04670     }
04671 
04672 
04682     protected function _preparePrice($dPrice, $dVat, $blCalculationModeNetto = null)
04683     {
04684         if ($blCalculationModeNetto === null) {
04685             $blCalculationModeNetto = $this->_isPriceViewModeNetto();
04686         }
04687 
04688         $oCurrency = $this->getConfig()->getActShopCurrencyObject();
04689 
04690         $blEnterNetPrice = $this->getConfig()->getConfigParam('blEnterNetPrice');
04691         if ($blCalculationModeNetto && !$blEnterNetPrice) {
04692             $dPrice = round(oxPrice::brutto2Netto($dPrice, $dVat), $oCurrency->decimal);
04693         } elseif (!$blCalculationModeNetto && $blEnterNetPrice) {
04694             $dPrice = round(oxPrice::netto2Brutto($dPrice, $dVat), $oCurrency->decimal);
04695         }
04696 
04697         return $dPrice;
04698     }
04699 
04705     protected function _getUserPriceSufix()
04706     {
04707         $sPriceSuffix = '';
04708         $oUser = $this->getArticleUser();
04709 
04710         if ($oUser) {
04711             if ($oUser->inGroup('oxidpricea')) {
04712                 $sPriceSuffix = 'a';
04713             } elseif ($oUser->inGroup('oxidpriceb')) {
04714                 $sPriceSuffix = 'b';
04715             } elseif ($oUser->inGroup('oxidpricec')) {
04716                 $sPriceSuffix = 'c';
04717             }
04718         }
04719 
04720         return $sPriceSuffix;
04721     }
04722 
04723 
04729     protected function _getPrice()
04730     {
04731         $sPriceSuffix = $this->_getUserPriceSufix();
04732         if ($sPriceSuffix === '') {
04733             $dPrice = $this->oxarticles__oxprice->value;
04734         } else {
04735             if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04736                 $dPrice = ($this->{oxarticles__oxprice . $sPriceSuffix}->value != 0) ? $this->{oxarticles__oxprice . $sPriceSuffix}->value : $this->oxarticles__oxprice->value;
04737             } else {
04738                 $dPrice = $this->{oxarticles__oxprice . $sPriceSuffix}->value;
04739             }
04740         }
04741 
04742         return $dPrice;
04743     }
04744 
04745 
04751     protected function _getVarMinPrice()
04752     {
04753         if ($this->_dVarMinPrice === null) {
04754             $dPrice = null;
04755 
04756 
04757             if (is_null($dPrice)) {
04758                 $sPriceSuffix = $this->_getUserPriceSufix();
04759                 if ($sPriceSuffix === '') {
04760                     $dPrice = $this->oxarticles__oxvarminprice->value;
04761                 } else {
04762                     $sSql = 'SELECT ';
04763                     if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04764                         $sSql .= 'MIN( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varminprice` ';
04765                     } else {
04766                         $sSql .= 'MIN(`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
04767                     }
04768 
04769                     $sSql .= ' FROM ' . $this->getViewName(true) . '
04770                     WHERE ' . $this->getSqlActiveSnippet(true) . '
04771                         AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
04772 
04773                     $dPrice = oxDb::getDb()->getOne($sSql);
04774                 }
04775             }
04776 
04777             $this->_dVarMinPrice = $dPrice;
04778         }
04779 
04780         return $this->_dVarMinPrice;
04781     }
04782 
04788     protected function _getSubShopVarMinPrice()
04789     {
04790         $myConfig = $this->getConfig();
04791         $sShopId = $myConfig->getShopId();
04792         if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
04793             $sPriceSuffix = $this->_getUserPriceSufix();
04794             $sSql = 'SELECT ';
04795             if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04796                 $sSql .= 'MIN(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varminprice` ';
04797             } else {
04798                 $sSql .= 'MIN(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
04799             }
04800             $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
04801                         INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
04802                         WHERE ' . $this->getSqlActiveSnippet(true) . '
04803                             AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
04804                             AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
04805             $dPrice = oxDb::getDb()->getOne($sSql);
04806         }
04807 
04808         return $dPrice;
04809     }
04810 
04816     protected function _getVarMaxPrice()
04817     {
04818         if ($this->_dVarMaxPrice === null) {
04819 
04820             $dPrice = null;
04821 
04822             if (is_null($dPrice)) {
04823                 $sPriceSuffix = $this->_getUserPriceSufix();
04824                 if ($sPriceSuffix === '') {
04825                     $dPrice = $this->oxarticles__oxvarmaxprice->value;
04826                 } else {
04827                     $sSql = 'SELECT ';
04828                     if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04829                         $sSql .= 'MAX( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varmaxprice` ';
04830                     } else {
04831                         $sSql .= 'MAX(`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
04832                     }
04833 
04834                     $sSql .= ' FROM ' . $this->getViewName(true) . '
04835                         WHERE ' . $this->getSqlActiveSnippet(true) . '
04836                             AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
04837 
04838                     $dPrice = oxDb::getDb()->getOne($sSql);
04839                 }
04840             }
04841 
04842             $this->_dVarMaxPrice = $dPrice;
04843         }
04844 
04845         return $this->_dVarMaxPrice;
04846     }
04847 
04853     protected function _getSubShopVarMaxPrice()
04854     {
04855         $myConfig = $this->getConfig();
04856         $sShopId = $myConfig->getShopId();
04857         if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
04858             $sPriceSuffix = $this->_getUserPriceSufix();
04859             $sSql = 'SELECT ';
04860             if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04861                 $sSql .= 'MAX(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varmaxprice` ';
04862             } else {
04863                 $sSql .= 'MAX(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
04864             }
04865             $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
04866                         INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
04867                         WHERE ' . $this->getSqlActiveSnippet(true) . '
04868                             AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
04869                             AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
04870             $dPrice = oxDb::getDb()->getOne($sSql);
04871         }
04872 
04873         return $dPrice;
04874     }
04875 
04883     protected function _loadFromDb($sOXID)
04884     {
04885 
04886         $sSelect = $this->buildSelectString(array($this->getViewName() . ".oxid" => $sOXID));
04887 
04888 
04889         $aData = oxDb::getDb(oxDb::FETCH_MODE_ASSOC)->getRow($sSelect);
04890 
04891         return $aData;
04892     }
04893 
04899     protected function _updateParentDependFields()
04900     {
04901         $oDb = oxDb::getDb();
04902 
04903         foreach ($this->_getCopyParentFields() as $sField) {
04904             $sValue = isset($this->$sField->value) ? $this->$sField->value : 0;
04905             $sSqlSets[] = '`' . str_replace('oxarticles__', '', $sField) . '` = ' . $oDb->quote($sValue);
04906         }
04907 
04908         $sSql = "UPDATE `oxarticles` SET ";
04909         $sSql .= implode(', ', $sSqlSets) . '';
04910         $sSql .= " WHERE `oxparentid` = " . $oDb->quote($this->getId());
04911 
04912         return $oDb->execute($sSql);
04913     }
04914 
04915 
04921     protected function _getCopyParentFields()
04922     {
04923         return $this->_aCopyParentField;
04924     }
04925 
04929     protected function _assignParentDependFields()
04930     {
04931         $sParent = $this->getParentArticle();
04932         if ($sParent) {
04933             foreach ($this->_getCopyParentFields() as $sField) {
04934                 $this->$sField = new oxField($sParent->$sField->value);
04935             }
04936         }
04937     }
04938 
04939 
04940 
04944     protected function _saveSortingFieldValuesOnLoad()
04945     {
04946         $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
04947         $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
04948 
04949         foreach ($aSortingFields as $sField) {
04950             $sFullField = $this->_getFieldLongName($sField);
04951             $this->_aSortingFieldsOnLoad[$sFullField] = $this->$sFullField->value;
04952         }
04953     }
04954 }