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 
00775 
00783     public function isMultilingualField($sFieldName)
00784     {
00785         switch ($sFieldName) {
00786             case "oxlongdesc":
00787             case "oxtags":
00788                 return true;
00789         }
00790 
00791         return parent::isMultilingualField($sFieldName);
00792     }
00793 
00800     public function getFUnitPrice()
00801     {
00802         if ($this->_fPricePerUnit == null) {
00803             if ($oPrice = $this->getUnitPrice()) {
00804                 if ($dPrice = $this->_getPriceForView($oPrice)) {
00805                     $this->_fPricePerUnit = oxRegistry::getLang()->formatCurrency($dPrice);
00806                 }
00807             }
00808         }
00809 
00810         return $this->_fPricePerUnit;
00811     }
00812 
00818     public function getUnitPrice()
00819     {
00820         // Performance
00821         if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
00822             return;
00823         }
00824 
00825         $oPrice = null;
00826         if ((double) $this->getUnitQuantity() && $this->oxarticles__oxunitname->value) {
00827             $oPrice = clone $this->getPrice();
00828             $oPrice->divide((double) $this->getUnitQuantity());
00829         }
00830 
00831         return $oPrice;
00832     }
00833 
00841     public function getFMinPrice()
00842     {
00843         $sPrice = '';
00844         if ($oPrice = $this->getMinPrice()) {
00845             $dPrice = $this->_getPriceForView($oPrice);
00846             $sPrice = oxRegistry::getLang()->formatCurrency($dPrice);
00847         }
00848 
00849         return $sPrice;
00850     }
00851 
00859     public function getFVarMinPrice()
00860     {
00861         $sPrice = '';
00862         if ($oPrice = $this->getVarMinPrice()) {
00863             $dPrice = $this->_getPriceForView($oPrice);
00864             $sPrice = oxRegistry::getLang()->formatCurrency($dPrice);
00865         }
00866 
00867         return $sPrice;
00868     }
00869 
00875     public function getVarMinPrice()
00876     {
00877         if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
00878             return;
00879         }
00880 
00881         $oPrice = null;
00882         $dPrice = $this->_getVarMinPrice();
00883 
00884         $dPrice = $this->_preparePrice($dPrice, $this->getArticleVat());
00885 
00886 
00887         $oPrice = $this->_getPriceObject();
00888         $oPrice->setPrice($dPrice);
00889         $this->_calculatePrice($oPrice);
00890 
00891 
00892         return $oPrice;
00893     }
00894 
00900     public function getMinPrice()
00901     {
00902         if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
00903             return;
00904         }
00905 
00906         $oPrice = null;
00907         $dPrice = $this->_getPrice();
00908         if ($this->_getVarMinPrice() !== null && $dPrice > $this->_getVarMinPrice()) {
00909             $dPrice = $this->_getVarMinPrice();
00910         }
00911 
00912         $dPrice = $this->_preparePrice($dPrice, $this->getArticleVat());
00913 
00914 
00915         $oPrice = $this->_getPriceObject();
00916         $oPrice->setPrice($dPrice);
00917         $this->_calculatePrice($oPrice);
00918 
00919         return $oPrice;
00920     }
00921 
00927     public function isRangePrice()
00928     {
00929         if ($this->_blIsRangePrice === null) {
00930 
00931             $this->setRangePrice(false);
00932 
00933             if ($this->_hasAnyVariant()) {
00934                 $dPrice = $this->_getPrice();
00935                 $dMinPrice = $this->_getVarMinPrice();
00936                 $dMaxPrice = $this->_getVarMaxPrice();
00937 
00938                 if ($dMinPrice != $dMaxPrice) {
00939                     $this->setRangePrice();
00940                 } elseif (!$this->isParentNotBuyable() && $dMinPrice != $dPrice) {
00941                     $this->setRangePrice();
00942                 }
00943             }
00944         }
00945 
00946         return $this->_blIsRangePrice;
00947     }
00948 
00949 
00957     public function setRangePrice($blIsRangePrice = true)
00958     {
00959         return $this->_blIsRangePrice = $blIsRangePrice;
00960     }
00961 
00967     public function isVisible()
00968     {
00969 
00970         // admin preview mode
00971         if (($blCanPreview = oxRegistry::getUtils()->canPreview()) !== null) {
00972             return $blCanPreview;
00973         }
00974 
00975         // active ?
00976         $sNow = date('Y-m-d H:i:s');
00977         if (!$this->oxarticles__oxactive->value &&
00978             ($this->oxarticles__oxactivefrom->value > $sNow ||
00979              $this->oxarticles__oxactiveto->value < $sNow
00980             )
00981         ) {
00982             return false;
00983         }
00984 
00985         // stock flags
00986         if ($this->getConfig()->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2) {
00987             $iOnStock = $this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value;
00988             if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
00989                 $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
00990             }
00991             if ($iOnStock <= 0) {
00992                 return false;
00993             }
00994         }
00995 
00996         return true;
00997     }
00998 
01007     public function assign($aRecord)
01008     {
01009         startProfile('articleAssign');
01010 
01011         // load object from database
01012         parent::assign($aRecord);
01013 
01014         $this->oxarticles__oxnid = $this->oxarticles__oxid;
01015 
01016         // check for simple article.
01017         if ($this->_blSkipAssign) {
01018             return;
01019         }
01020 
01021         $this->_assignParentFieldValues();
01022         $this->_assignNotBuyableParent();
01023 
01024 
01025         $this->_assignStock();
01026         $this->_assignPersistentParam();
01027         $this->_assignDynImageDir();
01028         $this->_assignComparisonListFlag();
01029 
01030 
01031         stopProfile('articleAssign');
01032     }
01033 
01034 
01045     public function load($sOXID)
01046     {
01047         // A. #1325 resetting to avoid problems when reloading (details etc)
01048         $this->_blNotBuyableParent = false;
01049 
01050 
01051         $aData = $this->_loadFromDb($sOXID);
01052 
01053         if ($aData) {
01054             $this->assign($aData);
01055 
01056             $this->_saveSortingFieldValuesOnLoad();
01057 
01058             $this->_iStockStatusOnLoad = $this->_iStockStatus;
01059 
01060             $this->_isLoaded = true;
01061 
01062             return true;
01063         }
01064 
01065         return false;
01066     }
01067 
01073     public function hasSortingFieldsChanged()
01074     {
01075         $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
01076         $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
01077         $blChanged = false;
01078         foreach ($aSortingFields as $sField) {
01079             $sParameterName = 'oxarticles__' . $sField;
01080             if ($this->$sParameterName->value !== $this->_aSortingFieldsOnLoad[$sParameterName]) {
01081                 $blChanged = true;
01082                 break;
01083             }
01084         }
01085 
01086         return $blChanged;
01087     }
01088 
01089 
01095     public function addToRatingAverage($iRating)
01096     {
01097         $dOldRating = $this->oxarticles__oxrating->value;
01098         $dOldCnt = $this->oxarticles__oxratingcnt->value;
01099         $this->oxarticles__oxrating->setValue(($dOldRating * $dOldCnt + $iRating) / ($dOldCnt + 1));
01100         $this->oxarticles__oxratingcnt->setValue($dOldCnt + 1);
01101         $dRating = ($dOldRating * $dOldCnt + $iRating) / ($dOldCnt + 1);
01102         $dRatingCnt = (int) ($dOldCnt + 1);
01103         // oxarticles.oxtimestamp = oxarticles.oxtimestamp to keep old timestamp value
01104         $oDb = oxDb::getDb();
01105         $oDb->execute('update oxarticles set oxarticles.oxrating = ' . $dRating . ',oxarticles.oxratingcnt = ' . $dRatingCnt . ', oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = ' . $oDb->quote($this->getId()));
01106 
01107     }
01108 
01114     public function setRatingAverage($iRating)
01115     {
01116         $this->oxarticles__oxrating = new oxField($iRating);
01117     }
01118 
01124     public function setRatingCount($iRatingCnt)
01125     {
01126         $this->oxarticles__oxratingcnt = new oxField($iRatingCnt);
01127     }
01128 
01136     public function getArticleRatingAverage($blIncludeVariants = false)
01137     {
01138         if (!$blIncludeVariants) {
01139             return round($this->oxarticles__oxrating->value, 1);
01140         } else {
01141             $oRating = oxNew('oxRating');
01142 
01143             return $oRating->getRatingAverage($this->getId(), 'oxarticle', $this->_getVariantsIds());
01144         }
01145     }
01146 
01154     public function getArticleRatingCount($blIncludeVariants = false)
01155     {
01156         if (!$blIncludeVariants) {
01157             return $this->oxarticles__oxratingcnt->value;
01158         } else {
01159             $oRating = oxNew('oxRating');
01160 
01161             return $oRating->getRatingCount($this->getId(), 'oxarticle', $this->_getVariantsIds());
01162         }
01163     }
01164 
01165 
01171     public function getReviews()
01172     {
01173         $aIds = array($this->getId());
01174 
01175         if ($this->oxarticles__oxparentid->value) {
01176             $aIds[] = $this->oxarticles__oxparentid->value;
01177         }
01178 
01179         // showing variant reviews ..
01180         if ($this->getConfig()->getConfigParam('blShowVariantReviews')) {
01181             $aAdd = $this->_getVariantsIds();
01182             if (is_array($aAdd)) {
01183                 $aIds = array_merge($aIds, $aAdd);
01184             }
01185         }
01186 
01187         $oReview = oxNew('oxreview');
01188         $oRevs = $oReview->loadList('oxarticle', $aIds);
01189 
01190         //if no review found, return null
01191         if ($oRevs->count() < 1) {
01192             return null;
01193         }
01194 
01195         return $oRevs;
01196     }
01197 
01203     public function getCrossSelling()
01204     {
01205         $oCrosslist = oxNew("oxarticlelist");
01206         $oCrosslist->loadArticleCrossSell($this->oxarticles__oxid->value);
01207         if ($oCrosslist->count()) {
01208             return $oCrosslist;
01209         }
01210     }
01211 
01217     public function getAccessoires()
01218     {
01219         $myConfig = $this->getConfig();
01220 
01221         // Performance
01222         if (!$myConfig->getConfigParam('bl_perfLoadAccessoires')) {
01223             return;
01224         }
01225 
01226         $oAcclist = oxNew("oxarticlelist");
01227         $oAcclist->setSqlLimit(0, $myConfig->getConfigParam('iNrofCrossellArticles'));
01228         $oAcclist->loadArticleAccessoires($this->oxarticles__oxid->value);
01229 
01230         if ($oAcclist->count()) {
01231             return $oAcclist;
01232         }
01233     }
01234 
01240     public function getSimilarProducts()
01241     {
01242         // Performance
01243         $myConfig = $this->getConfig();
01244         if (!$myConfig->getConfigParam('bl_perfLoadSimilar')) {
01245             return;
01246         }
01247 
01248         $sArticleTable = $this->getViewName();
01249 
01250         $sAttribs = '';
01251         $iCnt = 0;
01252         $this->_getAttribsString($sAttribs, $iCnt);
01253 
01254         if (!$sAttribs) {
01255             return null;
01256         }
01257 
01258         $aList = $this->_getSimList($sAttribs, $iCnt);
01259 
01260         if (count($aList)) {
01261             uasort($aList, 'cmpart');
01262 
01263             $sSearch = $this->_generateSimListSearchStr($sArticleTable, $aList);
01264 
01265             $oSimilarlist = oxNew('oxarticlelist');
01266             $oSimilarlist->setSqlLimit(0, $myConfig->getConfigParam('iNrofSimilarArticles'));
01267             $oSimilarlist->selectString($sSearch);
01268 
01269             return $oSimilarlist;
01270         }
01271     }
01272 
01278     public function getCustomerAlsoBoughtThisProducts()
01279     {
01280         // Performance
01281         $myConfig = $this->getConfig();
01282         if (!$myConfig->getConfigParam('bl_perfLoadCustomerWhoBoughtThis')) {
01283             return;
01284         }
01285 
01286         // selecting products that fits
01287         $sQ = $this->_generateSearchStrForCustomerBought();
01288 
01289         $oArticles = oxNew('oxarticlelist');
01290         $oArticles->setSqlLimit(0, $myConfig->getConfigParam('iNrofCustomerWhoArticles'));
01291         $oArticles->selectString($sQ);
01292         if ($oArticles->count()) {
01293             return $oArticles;
01294         }
01295     }
01296 
01303     public function loadAmountPriceInfo()
01304     {
01305         $myConfig = $this->getConfig();
01306         if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice || !$this->_blCalcPrice || !$this->hasAmountPrice()) {
01307             return array();
01308         }
01309 
01310         if ($this->_oAmountPriceInfo === null) {
01311             $this->_oAmountPriceInfo = array();
01312             if (count(($aAmPriceList = $this->_getAmountPriceList()->getArray()))) {
01313                 $this->_oAmountPriceInfo = $this->_fillAmountPriceList($aAmPriceList);
01314             }
01315         }
01316 
01317         return $this->_oAmountPriceInfo;
01318     }
01319 
01327     public function getSelectLists($sKeyPrefix = null)
01328     {
01329         //#1468C - more then one article in basket with different selectlist...
01330         //optionall function parameter $sKeyPrefix added, used only in basket.php
01331         $sKey = $this->getId();
01332         if (isset($sKeyPrefix)) {
01333             $sKey = $sKeyPrefix . '__' . $sKey;
01334         }
01335 
01336         if (!isset(self::$_aSelList[$sKey])) {
01337             $oDb = oxDb::getDb();
01338             $sSLViewName = getViewName('oxselectlist');
01339 
01340             $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
01341                    where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
01342 
01343             // all selectlists this article has
01344             $oLists = oxNew('oxlist');
01345             $oLists->init('oxselectlist');
01346             $oLists->selectString(sprintf($sQ, $oDb->quote($this->getId())));
01347 
01348             //#1104S if this is variant ant it has no selectlists, trying with parent
01349             if ($oLists->count() == 0 && $this->oxarticles__oxparentid->value) {
01350                 $oLists->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
01351             }
01352 
01353             // We do not need to calculate price here as there are method to get current article vat
01354             /*if ( $this->getPrice() != null ) {
01355                 $dVat = $this->getPrice()->getVat();
01356             }*/
01357             $dVat = $this->getArticleVat();
01358 
01359             $iCnt = 0;
01360             self::$_aSelList[$sKey] = array();
01361             foreach ($oLists as $oSelectlist) {
01362                 self::$_aSelList[$sKey][$iCnt] = $oSelectlist->getFieldList($dVat);
01363                 self::$_aSelList[$sKey][$iCnt]['name'] = $oSelectlist->oxselectlist__oxtitle->value;
01364                 $iCnt++;
01365             }
01366         }
01367 
01368         return self::$_aSelList[$sKey];
01369     }
01370 
01376     public function getVariantsCount()
01377     {
01378         return $this->oxarticles__oxvarcount->value;
01379     }
01380 
01386     public function hasMdVariants()
01387     {
01388         return $this->_blHasMdVariants;
01389     }
01390 
01396     public function hasIntangibleAgreement()
01397     {
01398         return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxnonmaterial->value && !$this->hasDownloadableAgreement();
01399     }
01400 
01406     public function hasDownloadableAgreement()
01407     {
01408         return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxisdownloadable->value;
01409     }
01410 
01420     public function getVariantSelections($aFilterIds = null, $sActVariantId = null, $iLimit = 0)
01421     {
01422         $iLimit = (int) $iLimit;
01423         if (!isset($this->_aVariantSelections[$iLimit])) {
01424             $aVariantSelections = false;
01425             if ($this->oxarticles__oxvarcount->value) {
01426                 $oVariants = $this->getVariants(false);
01427                 $aVariantSelections = oxNew("oxVariantHandler")->buildVariantSelections($this->oxarticles__oxvarname->getRawValue(), $oVariants, $aFilterIds, $sActVariantId, $iLimit);
01428 
01429                 if (!empty($oVariants) && empty($aVariantSelections['rawselections'])) {
01430                     $aVariantSelections = false;
01431                 }
01432             }
01433             $this->_aVariantSelections[$iLimit] = $aVariantSelections;
01434         }
01435 
01436         return $this->_aVariantSelections[$iLimit];
01437     }
01438 
01447     public function getSelections($iLimit = null, $aFilter = null)
01448     {
01449         $sId = $this->getId() . ((int) $iLimit);
01450         if (!array_key_exists($sId, self::$_aSelections)) {
01451 
01452             $oDb = oxDb::getDb();
01453             $sSLViewName = getViewName('oxselectlist');
01454 
01455             $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
01456                    where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
01457 
01458             if (($iLimit = (int) $iLimit)) {
01459                 $sQ .= " limit $iLimit ";
01460             }
01461 
01462             // vat value for price
01463             $dVat = 0;
01464             if (($oPrice = $this->getPrice()) != null) {
01465                 $dVat = $oPrice->getVat();
01466             }
01467 
01468             // all selectlists this article has
01469             $oList = oxNew('oxlist');
01470             $oList->init('oxselectlist');
01471             $oList->getBaseObject()->setVat($dVat);
01472             $oList->selectString(sprintf($sQ, $oDb->quote($this->getId())));
01473 
01474             //#1104S if this is variant and it has no selectlists, trying with parent
01475             if ($oList->count() == 0 && $this->oxarticles__oxparentid->value) {
01476                 $oList->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
01477             }
01478 
01479             self::$_aSelections[$sId] = $oList->count() ? $oList : false;
01480         }
01481 
01482         if (self::$_aSelections[$sId]) {
01483             // marking active from filter
01484             $aFilter = ($aFilter === null) ? oxRegistry::getConfig()->getRequestParameter("sel") : $aFilter;
01485             if ($aFilter) {
01486                 $iSelIdx = 0;
01487                 foreach (self::$_aSelections[$sId] as $oSelection) {
01488                     if (isset($aFilter[$iSelIdx])) {
01489                         $oSelection->setActiveSelectionByIndex($aFilter[$iSelIdx]);
01490                     }
01491                     $iSelIdx++;
01492                 }
01493             }
01494         }
01495 
01496         return self::$_aSelections[$sId];
01497     }
01498 
01507     public function getFullVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
01508     {
01509         return $this->_loadVariantList(false, $blRemoveNotOrderables, $blForceCoreTable);
01510     }
01511 
01521     public function getVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
01522     {
01523         return $this->_loadVariantList($this->_isInList(), $blRemoveNotOrderables, $blForceCoreTable);
01524     }
01525 
01531     public function getSimpleVariants()
01532     {
01533         if ($this->oxarticles__oxvarcount->value) {
01534             return $this->getVariants();
01535         }
01536     }
01537 
01546     public function getAdminVariants($sLanguage = null)
01547     {
01548         $oVariants = oxNew('oxarticlelist');
01549         if (($sId = $this->getId())) {
01550 
01551             $oBaseObj = $oVariants->getBaseObject();
01552 
01553             if (is_null($sLanguage)) {
01554                 $oBaseObj->setLanguage(oxRegistry::getLang()->getBaseLanguage());
01555             } else {
01556                 $oBaseObj->setLanguage($sLanguage);
01557             }
01558 
01559             $sSql = "select * from " . $oBaseObj->getViewName() . " where oxparentid = '{$sId}' order by oxsort ";
01560             $oVariants->selectString($sSql);
01561 
01562             //if we have variants then depending on config option the parent may be non buyable
01563             if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && ($oVariants->count() > 0)) {
01564                 //$this->blNotBuyable = true;
01565                 $this->_blNotBuyableParent = true;
01566             }
01567         }
01568 
01569         return $oVariants;
01570     }
01571 
01579     public function getCategory()
01580     {
01581         $oCategory = oxNew('oxcategory');
01582         $oCategory->setLanguage($this->getLanguage());
01583 
01584         // variant handling
01585         $sOXID = $this->getId();
01586         if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01587             $sOXID = $this->oxarticles__oxparentid->value;
01588         }
01589 
01590         if ($sOXID) {
01591             // if the oxcategory instance of this article is not cached
01592             if (!isset($this->_aCategoryCache[$sOXID])) {
01593                 startPRofile('getCategory');
01594                 $oStr = getStr();
01595                 $sWhere = $oCategory->getSqlActiveSnippet();
01596                 $sSelect = $this->_generateSearchStr($sOXID);
01597                 $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " order by oxobject2category.oxtime limit 1";
01598 
01599                 // category not found ?
01600                 if (!$oCategory->assignRecord($sSelect)) {
01601 
01602                     $sSelect = $this->_generateSearchStr($sOXID, true);
01603                     $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " limit 1";
01604 
01605                     // looking for price category
01606                     if (!$oCategory->assignRecord($sSelect)) {
01607                         $oCategory = null;
01608                     }
01609                 }
01610                 // add the category instance to cache
01611                 $this->_aCategoryCache[$sOXID] = $oCategory;
01612                 stopPRofile('getCategory');
01613             } else {
01614                 // if the oxcategory instance is cached
01615                 $oCategory = $this->_aCategoryCache[$sOXID];
01616             }
01617         }
01618 
01619         return $oCategory;
01620     }
01621 
01630     public function getCategoryIds($blActCats = false, $blSkipCache = false)
01631     {
01632         $sArticleId = $this->getId();
01633 
01634         if (!isset(self::$_aArticleCats[$sArticleId]) || $blSkipCache) {
01635 
01636             $sSql = $this->_getCategoryIdsSelect($blActCats);
01637             $aCategoryIds = $this->_selectCategoryIds($sSql, 'oxcatnid');
01638 
01639             $sSql = $this->getSqlForPriceCategories();
01640             $aPriceCategoryIds = $this->_selectCategoryIds($sSql, 'oxid');
01641 
01642             self::$_aArticleCats[$sArticleId] = array_unique(array_merge($aCategoryIds, $aPriceCategoryIds));
01643         }
01644 
01645         return self::$_aArticleCats[$sArticleId];
01646     }
01647 
01657     public function getVendor($blShopCheck = true)
01658     {
01659         if (($sVendorId = $this->getVendorId())) {
01660             $oVendor = oxNew('oxvendor');
01661         } elseif (!$blShopCheck && $this->oxarticles__oxvendorid->value) {
01662             $oVendor = oxNew('oxi18n');
01663             $oVendor->init('oxvendor');
01664             $oVendor->setReadOnly(true);
01665             $sVendorId = $this->oxarticles__oxvendorid->value;
01666         }
01667         if ($sVendorId && $oVendor->load($sVendorId) && $oVendor->oxvendor__oxactive->value) {
01668 
01669             return $oVendor;
01670         }
01671 
01672         return null;
01673     }
01674 
01682     public function getVendorId($blForceReload = false)
01683     {
01684         $sVendorId = false;
01685         if ($this->oxarticles__oxvendorid->value) {
01686             $sVendorId = $this->oxarticles__oxvendorid->value;
01687 
01688         }
01689 
01690         return $sVendorId;
01691     }
01692 
01700     public function getManufacturerId($blForceReload = false)
01701     {
01702         $sManufacturerId = false;
01703         if ($this->oxarticles__oxmanufacturerid->value) {
01704 
01705             $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
01706 
01707         }
01708 
01709         return $sManufacturerId;
01710     }
01711 
01721     public function getManufacturer($blShopCheck = true)
01722     {
01723         $oManufacturer = oxNew('oxmanufacturer');
01724         if (!($sManufacturerId = $this->getManufacturerId()) &&
01725             !$blShopCheck && $this->oxarticles__oxmanufacturerid->value
01726         ) {
01727             $oManufacturer->setReadOnly(true);
01728             $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
01729         }
01730 
01731         if ($sManufacturerId && $oManufacturer->load($sManufacturerId)) {
01732             if (!$this->getConfig()->getConfigParam('bl_perfLoadManufacturerTree')) {
01733                 $oManufacturer->setReadOnly(true);
01734             }
01735             $oManufacturer = $oManufacturer->oxmanufacturers__oxactive->value ? $oManufacturer : null;
01736         } else {
01737             $oManufacturer = null;
01738         }
01739 
01740         return $oManufacturer;
01741     }
01742 
01750     public function inCategory($sCatNid)
01751     {
01752         return in_array($sCatNid, $this->getCategoryIds());
01753     }
01754 
01763     public function isAssignedToCategory($sCatId)
01764     {
01765         // variant handling
01766         $sOXID = $this->getId();
01767         if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
01768             $sOXID = $this->oxarticles__oxparentid->value;
01769         }
01770 
01771         $oDb = oxDb::getDb();
01772         $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId);
01773         $sOXID = $oDb->getOne($sSelect);
01774         // article is assigned to passed category!
01775         if (isset($sOXID) && $sOXID) {
01776             return true;
01777         }
01778 
01779         // maybe this category is price category ?
01780         if ($this->getConfig()->getConfigParam('bl_perfLoadPrice') && $this->_blLoadPrice) {
01781             $dPriceFromTo = $this->getPrice()->getBruttoPrice();
01782             if ($dPriceFromTo > 0) {
01783                 $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo);
01784                 $sOXID = $oDb->getOne($sSelect);
01785                 // article is assigned to passed category!
01786                 if (isset($sOXID) && $sOXID) {
01787                     return true;
01788                 }
01789             }
01790         }
01791 
01792         return false;
01793     }
01794 
01800     public function getTPrice()
01801     {
01802         if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
01803             return;
01804         }
01805 
01806         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01807         if ($this->_oTPrice !== null) {
01808             return $this->_oTPrice;
01809         }
01810 
01811         $oPrice = $this->_getPriceObject();
01812 
01813         $dBasePrice = $this->oxarticles__oxtprice->value;
01814         $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
01815 
01816         $oPrice->setPrice($dBasePrice);
01817 
01818         $this->_applyVat($oPrice, $this->getArticleVat());
01819         $this->_applyCurrency($oPrice);
01820 
01821         if ($this->isParentNotBuyable()) {
01822             // if parent article is not buyable then compare agains min article variant price
01823             $oPrice2 = $this->getVarMinPrice();
01824         } else {
01825             // else compare against article price
01826             $oPrice2 = $this->getPrice();
01827         }
01828 
01829         if ($oPrice->getPrice() <= $oPrice2->getPrice()) {
01830             // if RRP price is less or equal to comparable price then return
01831             return;
01832         }
01833 
01834         $this->_oTPrice = $oPrice;
01835 
01836         return $this->_oTPrice;
01837     }
01838 
01844     public function skipDiscounts()
01845     {
01846         // already loaded skip discounts config
01847         if ($this->_blSkipDiscounts !== null) {
01848             return $this->_blSkipDiscounts;
01849         }
01850 
01851         if ($this->oxarticles__oxskipdiscounts->value) {
01852             return true;
01853         }
01854 
01855 
01856         $this->_blSkipDiscounts = false;
01857         if (oxRegistry::get("oxDiscountList")->hasSkipDiscountCategories()) {
01858 
01859             $oDb = oxDb::getDb();
01860             $sO2CView = getViewName('oxobject2category', $this->getLanguage());
01861             $sViewName = getViewName('oxcategories', $this->getLanguage());
01862             $sSelect = "select 1 from $sO2CView as $sO2CView left join {$sViewName} on {$sViewName}.oxid = $sO2CView.oxcatnid
01863                          where $sO2CView.oxobjectid=" . $oDb->quote($this->getId()) . " and {$sViewName}.oxactive = 1 and {$sViewName}.oxskipdiscounts = '1' ";
01864             $this->_blSkipDiscounts = ($oDb->getOne($sSelect) == 1);
01865         }
01866 
01867         return $this->_blSkipDiscounts;
01868     }
01869 
01875     public function setPrice(oxPrice $oPrice)
01876     {
01877         $this->_oPrice = $oPrice;
01878     }
01879 
01888     public function getBasePrice($dAmount = 1)
01889     {
01890         // override this function if you want e.g. different prices
01891         // for diff. user groups.
01892 
01893         // Performance
01894         $myConfig = $this->getConfig();
01895         if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
01896             return;
01897         }
01898 
01899         // GroupPrice or DB price ajusted by AmountPrice
01900         $dPrice = $this->_getAmountPrice($dAmount);
01901 
01902 
01903         return $dPrice;
01904     }
01905 
01913     public function getPrice($dAmount = 1)
01914     {
01915         $myConfig = $this->getConfig();
01916         // Performance
01917         if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
01918             return;
01919         }
01920 
01921         // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
01922         if ($dAmount != 1 || $this->_oPrice === null) {
01923 
01924             // module
01925             $dBasePrice = $this->getBasePrice($dAmount);
01926             $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
01927 
01928             $oPrice = $this->_getPriceObject();
01929 
01930             $oPrice->setPrice($dBasePrice);
01931 
01932             // price handling
01933             if (!$this->_blCalcPrice && $dAmount == 1) {
01934                 return $this->_oPrice = $oPrice;
01935             }
01936 
01937             $this->_calculatePrice($oPrice);
01938             if ($dAmount != 1) {
01939                 return $oPrice;
01940             }
01941 
01942             $this->_oPrice = $oPrice;
01943         }
01944 
01945         return $this->_oPrice;
01946     }
01947 
01953     public function setArticleUser($oUser)
01954     {
01955         $this->_oUser = $oUser;
01956     }
01957 
01963     public function getArticleUser()
01964     {
01965         if ($this->_oUser) {
01966             return $this->_oUser;
01967         }
01968 
01969         return $this->getUser();
01970     }
01971 
01981     public function getBasketPrice($dAmount, $aSelList, $oBasket)
01982     {
01983         $oUser = $oBasket->getBasketUser();
01984         $this->setArticleUser($oUser);
01985 
01986         $oBasketPrice = $this->_getPriceObject($oBasket->isCalculationModeNetto());
01987 
01988         // get base price
01989         $dBasePrice = $this->getBasePrice($dAmount);
01990 
01991         $dBasePrice = $this->_modifySelectListPrice($dBasePrice, $aSelList);
01992         $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat(), $oBasket->isCalculationModeNetto());
01993 
01994         // applying select list price
01995 
01996         // setting price
01997         $oBasketPrice->setPrice($dBasePrice);
01998 
01999         $dVat = oxRegistry::get("oxVatSelector")->getBasketItemVat($this, $oBasket);
02000         $this->_calculatePrice($oBasketPrice, $dVat);
02001 
02002         // returning final price object
02003         return $oBasketPrice;
02004     }
02005 
02014     public function delete($sOXID = null)
02015     {
02016         if (!$sOXID) {
02017             $sOXID = $this->getId();
02018         }
02019         if (!$sOXID) {
02020             return false;
02021         }
02022 
02023 
02024 
02025         // #2339 delete first variants before deleting parent product
02026         $this->_deleteVariantRecords($sOXID);
02027         $this->load($sOXID);
02028         $this->_deletePics();
02029         $this->_onChangeResetCounts($sOXID, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
02030 
02031         // delete self
02032         parent::delete($sOXID);
02033 
02034         $rs = $this->_deleteRecords($sOXID);
02035 
02036         oxRegistry::get("oxSeoEncoderArticle")->onDeleteArticle($this);
02037 
02038         $this->onChange(ACTION_DELETE, $sOXID, $this->oxarticles__oxparentid->value);
02039 
02040         return $rs->EOF;
02041     }
02042 
02051     public function reduceStock($dAmount, $blAllowNegativeStock = false)
02052     {
02053         $this->beforeUpdate();
02054 
02055         $iStockCount = $this->oxarticles__oxstock->value - $dAmount;
02056         if (!$blAllowNegativeStock && ($iStockCount < 0)) {
02057             $dAmount += $iStockCount;
02058             $iStockCount = 0;
02059         }
02060         $this->oxarticles__oxstock = new oxField($iStockCount);
02061 
02062         $oDb = oxDb::getDb();
02063         $oDb->execute('update oxarticles set oxarticles.oxstock = ' . $oDb->quote($iStockCount) . ' where oxarticles.oxid = ' . $oDb->quote($this->getId()));
02064         $this->onChange(ACTION_UPDATE_STOCK);
02065 
02066         return $dAmount;
02067     }
02068 
02077     public function updateSoldAmount($dAmount = 0)
02078     {
02079         if (!$dAmount) {
02080             return;
02081         }
02082 
02083         // article is not variant - should be updated current amount
02084         if (!$this->oxarticles__oxparentid->value) {
02085             //updating by SQL query, due to wrong behaviour if saving article using not admin mode
02086             $dAmount = (double) $dAmount;
02087             $oDb = oxDb::getDb();
02088             $rs = $oDb->execute("update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $dAmount where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
02089         } elseif ($this->oxarticles__oxparentid->value) {
02090             // article is variant - should be updated this article parent amount
02091             $oUpdateArticle = $this->getParentArticle();
02092             if ($oUpdateArticle) {
02093                 $oUpdateArticle->updateSoldAmount($dAmount);
02094             }
02095         }
02096 
02097         return $rs;
02098     }
02099 
02105     public function disableReminder()
02106     {
02107         $oDb = oxDb::getDb();
02108 
02109         return $oDb->execute("update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
02110     }
02111 
02117     public function save()
02118     {
02119         $this->_assignParentDependFields();
02120 
02121         if (($blRet = parent::save())) {
02122             // saving long description
02123             $this->_saveArtLongDesc();
02124         }
02125 
02126         return $blRet;
02127     }
02128 
02132     public function resetParent()
02133     {
02134         $sParentId = $this->oxarticles__oxparentid->value;
02135         $this->oxarticles__oxparentid = new oxField('', oxField::T_RAW);
02136         $this->_blAllowEmptyParentId = true;
02137         $this->save();
02138         $this->_blAllowEmptyParentId = false;
02139 
02140         if ($sParentId !== '') {
02141             $this->onChange(ACTION_UPDATE, null, $sParentId);
02142         }
02143     }
02144 
02145 
02152     public function getPictureGallery()
02153     {
02154         $myConfig = $this->getConfig();
02155 
02156         //initialize
02157         $blMorePic = false;
02158         $aArtPics = array();
02159         $aArtIcons = array();
02160         $iActPicId = 1;
02161         $sActPic = $this->getPictureUrl($iActPicId);
02162 
02163         if (oxRegistry::getConfig()->getRequestParameter('actpicid')) {
02164             $iActPicId = oxRegistry::getConfig()->getRequestParameter('actpicid');
02165         }
02166 
02167         $oStr = getStr();
02168         $iCntr = 0;
02169         $iPicCount = $myConfig->getConfigParam('iPicCount');
02170         $blCheckActivePicId = true;
02171 
02172         for ($i = 1; $i <= $iPicCount; $i++) {
02173             $sPicVal = $this->getPictureUrl($i);
02174             $sIcoVal = $this->getIconUrl($i);
02175             if (!$oStr->strstr($sIcoVal, 'nopic_ico.jpg') && !$oStr->strstr($sIcoVal, 'nopic.jpg') &&
02176                 !$oStr->strstr($sPicVal, 'nopic_ico.jpg') && !$oStr->strstr($sPicVal, 'nopic.jpg')
02177             ) {
02178                 if ($iCntr) {
02179                     $blMorePic = true;
02180                 }
02181                 $aArtIcons[$i] = $sIcoVal;
02182                 $aArtPics[$i] = $sPicVal;
02183                 $iCntr++;
02184 
02185                 if ($iActPicId == $i) {
02186                     $sActPic = $sPicVal;
02187                     $blCheckActivePicId = false;
02188                 }
02189 
02190             } elseif ($blCheckActivePicId && $iActPicId <= $i) {
02191                 // if picture is empty, setting active pic id to next
02192                 // picture
02193                 $iActPicId++;
02194             }
02195         }
02196 
02197         $blZoomPic = false;
02198         $aZoomPics = array();
02199         $iZoomPicCount = $myConfig->getConfigParam('iPicCount');
02200 
02201         for ($j = 1, $c = 1; $j <= $iZoomPicCount; $j++) {
02202             $sVal = $this->getZoomPictureUrl($j);
02203 
02204             if ($sVal && !$oStr->strstr($sVal, 'nopic.jpg')) {
02205                 $blZoomPic = true;
02206                 $aZoomPics[$c]['id'] = $c;
02207                 $aZoomPics[$c]['file'] = $sVal;
02208                 //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
02209                 if (!$sVal) {
02210                     $aZoomPics[$c]['file'] = "nopic.jpg";
02211                 }
02212                 $c++;
02213             }
02214         }
02215 
02216         $aPicGallery = array('ActPicID' => $iActPicId,
02217                              'ActPic'   => $sActPic,
02218                              'MorePics' => $blMorePic,
02219                              'Pics'     => $aArtPics,
02220                              'Icons'    => $aArtIcons,
02221                              'ZoomPic'  => $blZoomPic,
02222                              'ZoomPics' => $aZoomPics);
02223 
02224         return $aPicGallery;
02225     }
02226 
02240     public function onChange($sAction = null, $sOXID = null, $sParentID = null)
02241     {
02242         $myConfig = $this->getConfig();
02243 
02244         if (!isset($sOXID)) {
02245             if ($this->getId()) {
02246                 $sOXID = $this->getId();
02247             }
02248             if (!isset ($sOXID)) {
02249                 $sOXID = $this->oxarticles__oxid->value;
02250             }
02251             if ($this->oxarticles__oxparentid->value) {
02252                 $sParentID = $this->oxarticles__oxparentid->value;
02253             }
02254         }
02255         if (!isset($sOXID)) {
02256             return;
02257         }
02258 
02259         //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
02260         if ($myConfig->getConfigParam('blUseStock')) {
02261             //if article has variants then updating oxvarstock field
02262             //getting parent id
02263             if (!isset($sParentID)) {
02264                 $oDb = oxDb::getDb();
02265                 $sQ = 'select oxparentid from oxarticles where oxid = ' . $oDb->quote($sOXID);
02266                 $sParentID = $oDb->getOne($sQ);
02267             }
02268             //if we have parent id then update stock
02269             if ($sParentID) {
02270                 $this->_onChangeUpdateStock($sParentID);
02271             }
02272         }
02273         //if we have parent id then update count
02274         //update count even if blUseStock is not active
02275         if ($sParentID) {
02276             $this->_onChangeUpdateVarCount($sParentID);
02277         }
02278 
02279         $sId = ($sParentID) ? $sParentID : $sOXID;
02280         $this->_setVarMinMaxPrice($sId);
02281 
02282         $this->_updateParentDependFields();
02283 
02284         // resetting articles count cache if stock has changed and some
02285         // articles goes offline (M:1448)
02286         if ($sAction === ACTION_UPDATE_STOCK) {
02287             $this->_assignStock();
02288             $this->_onChangeStockResetCount($sOXID);
02289         }
02290 
02291     }
02292 
02299     public function getCustomVAT()
02300     {
02301         if (isset($this->oxarticles__oxvat->value)) {
02302             return $this->oxarticles__oxvat->value;
02303         }
02304     }
02305 
02314     public function checkForStock($dAmount, $dArtStockAmount = 0)
02315     {
02316         $myConfig = $this->getConfig();
02317         if (!$myConfig->getConfigParam('blUseStock')) {
02318             return true;
02319         }
02320 
02321         $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
02322         // fetching DB info as its up-to-date
02323         $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = ' . $oDb->quote($this->getId());
02324         $rs = $oDb->select($sQ);
02325 
02326         $iOnStock = 0;
02327         $iStockFlag = 0;
02328         if ($rs !== false && $rs->recordCount() > 0) {
02329             $iOnStock = $rs->fields['oxstock'] - $dArtStockAmount;
02330             $iStockFlag = $rs->fields['oxstockflag'];
02331 
02332             // foreign stock is also always considered as on stock
02333             if ($iStockFlag == 1 || $iStockFlag == 4) {
02334                 return true;
02335             }
02336             if (!$myConfig->getConfigParam('blAllowUnevenAmounts')) {
02337                 $iOnStock = floor($iOnStock);
02338             }
02339         }
02340         if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
02341             $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
02342         }
02343         if ($iOnStock >= $dAmount) {
02344             return true;
02345         } else {
02346             if ($iOnStock > 0) {
02347                 return $iOnStock;
02348             } else {
02349                 $oEx = oxNew('oxArticleInputException');
02350                 $oEx->setMessage('ERROR_MESSAGE_ARTICLE_ARTICLE_NOT_BUYABLE');
02351                 oxRegistry::get("oxUtilsView")->addErrorToDisplay($oEx);
02352 
02353                 return false;
02354             }
02355         }
02356     }
02357 
02358 
02364     public function getLongDescription()
02365     {
02366         if ($this->_oLongDesc === null) {
02367             // initializing
02368             $this->_oLongDesc = new oxField();
02369 
02370 
02371             // choosing which to get..
02372             $sOxid = $this->getId();
02373             $sViewName = getViewName('oxartextends', $this->getLanguage());
02374 
02375             $oDb = oxDb::getDb();
02376             $sDbValue = $oDb->getOne("select oxlongdesc from {$sViewName} where oxid = " . $oDb->quote($sOxid));
02377 
02378             if ($sDbValue != false) {
02379                 $this->_oLongDesc->setValue($sDbValue, oxField::T_RAW);
02380             } elseif ($this->oxarticles__oxparentid->value) {
02381                 if (!$this->isAdmin() || $this->_blLoadParentData) {
02382                     $oParent = $this->getParentArticle();
02383                     if ($oParent) {
02384                         $this->_oLongDesc->setValue($oParent->getLongDescription()->getRawValue(), oxField::T_RAW);
02385                     }
02386                 }
02387             }
02388         }
02389 
02390         return $this->_oLongDesc;
02391     }
02392 
02399     public function getLongDesc()
02400     {
02401         return oxRegistry::get("oxUtilsView")->parseThroughSmarty($this->getLongDescription()->getRawValue(), $this->getId() . $this->getLanguage(), null, true);
02402     }
02403 
02411             public function setArticleLongDesc($sDesc)
02412             {
02413 
02414                 // setting current value
02415                 $this->_oLongDesc = new oxField($sDesc, oxField::T_RAW);
02416                 $this->oxarticles__oxlongdesc = new oxField($sDesc, oxField::T_RAW);
02417             }
02418 
02424     public function getAttributes()
02425     {
02426         if ($this->_oAttributeList === null) {
02427             $this->_oAttributeList = oxNew('oxattributelist');
02428             $this->_oAttributeList->loadAttributes($this->getId(), $this->getParentId());
02429         }
02430 
02431         return $this->_oAttributeList;
02432     }
02433 
02439     public function getAttributesDisplayableInBasket()
02440     {
02441         if ($this->_oAttributeList === null) {
02442             $this->_oAttributeList = oxNew('oxattributelist');
02443             $this->_oAttributeList->loadAttributesDisplayableInBasket($this->getId(), $this->getParentId());
02444         }
02445 
02446         return $this->_oAttributeList;
02447     }
02448 
02449 
02456     public function appendLink($sAddParams, $iLang = null)
02457     {
02458         if ($sAddParams) {
02459             if ($iLang === null) {
02460                 $iLang = $this->getLanguage();
02461             }
02462 
02463             $this->_aSeoAddParams[$iLang] = isset($this->_aSeoAddParams[$iLang]) ? $this->_aSeoAddParams[$iLang] . "&amp;" : "";
02464             $this->_aSeoAddParams[$iLang] .= $sAddParams;
02465         }
02466     }
02467 
02476     public function getBaseSeoLink($iLang, $blMain = false)
02477     {
02479         $oEncoder = oxRegistry::get("oxSeoEncoderArticle");
02480         if (!$blMain) {
02481             return $oEncoder->getArticleUrl($this, $iLang, $this->getLinkType());
02482         }
02483 
02484         return $oEncoder->getArticleMainUrl($this, $iLang);
02485     }
02486 
02495     public function getLink($iLang = null, $blMain = false)
02496     {
02497         if (!oxRegistry::getUtils()->seoIsActive()) {
02498             return $this->getStdLink($iLang);
02499         }
02500 
02501         if ($iLang === null) {
02502             $iLang = $this->getLanguage();
02503         }
02504 
02505         $iLinkType = $this->getLinkType();
02506         if (!isset($this->_aSeoUrls[$iLang][$iLinkType])) {
02507             $this->_aSeoUrls[$iLang][$iLinkType] = $this->getBaseSeoLink($iLang, $blMain);
02508         }
02509 
02510         $sUrl = $this->_aSeoUrls[$iLang][$iLinkType];
02511         if (isset($this->_aSeoAddParams[$iLang])) {
02512             $sUrl .= ((strpos($sUrl . $this->_aSeoAddParams[$iLang], '?') === false) ? '?' : '&amp;') . $this->_aSeoAddParams[$iLang];
02513         }
02514 
02515         return $sUrl;
02516     }
02517 
02526     public function getMainLink($iLang = null)
02527     {
02528         return $this->getLink($iLang, true);
02529     }
02530 
02536     public function setLinkType($iType)
02537     {
02538         // resetting details link, to force new
02539         $this->_sDetailLink = null;
02540 
02541         // setting link type
02542         $this->_iLinkType = (int) $iType;
02543     }
02544 
02550     public function getLinkType()
02551     {
02552         return $this->_iLinkType;
02553     }
02554 
02561     public function appendStdLink($sAddParams, $iLang = null)
02562     {
02563         if ($sAddParams) {
02564             if ($iLang === null) {
02565                 $iLang = $this->getLanguage();
02566             }
02567 
02568             $this->_aStdAddParams[$iLang] = isset($this->_aStdAddParams[$iLang]) ? $this->_aStdAddParams[$iLang] . "&amp;" : "";
02569             $this->_aStdAddParams[$iLang] .= $sAddParams;
02570         }
02571     }
02572 
02582     public function getBaseStdLink($iLang, $blAddId = true, $blFull = true)
02583     {
02584         $sUrl = '';
02585         if ($blFull) {
02586             //always returns shop url, not admin
02587             $sUrl = $this->getConfig()->getShopUrl($iLang, false);
02588         }
02589 
02590         $sUrl .= "index.php?cl=details" . ($blAddId ? "&amp;anid=" . $this->getId() : "");
02591 
02592         return $sUrl . (isset($this->_aStdAddParams[$iLang]) ? "&amp;" . $this->_aStdAddParams[$iLang] : "");
02593     }
02594 
02603     public function getStdLink($iLang = null, $aParams = array())
02604     {
02605         if ($iLang === null) {
02606             $iLang = $this->getLanguage();
02607         }
02608 
02609         if (!isset($this->_aStdUrls[$iLang])) {
02610             $this->_aStdUrls[$iLang] = $this->getBaseStdLink($iLang);
02611         }
02612 
02613         return oxRegistry::get("oxUtilsUrl")->processUrl($this->_aStdUrls[$iLang], true, $aParams, $iLang);
02614     }
02615 
02621     public function getMediaUrls()
02622     {
02623         if ($this->_aMediaUrls === null) {
02624             $this->_aMediaUrls = oxNew("oxlist");
02625             $this->_aMediaUrls->init("oxmediaurl");
02626             $this->_aMediaUrls->getBaseObject()->setLanguage($this->getLanguage());
02627 
02628             $sViewName = getViewName("oxmediaurls", $this->getLanguage());
02629             $sQ = "select * from {$sViewName} where oxobjectid = '" . $this->getId() . "'";
02630             $this->_aMediaUrls->selectString($sQ);
02631         }
02632 
02633         return $this->_aMediaUrls;
02634     }
02635 
02641     public function getDynImageDir()
02642     {
02643         return $this->_sDynImageDir;
02644     }
02645 
02651     public function getDispSelList()
02652     {
02653         if ($this->_aDispSelList === null) {
02654             if ($this->getConfig()->getConfigParam('bl_perfLoadSelectLists') && $this->getConfig()->getConfigParam('bl_perfLoadSelectListsInAList')) {
02655                 $this->_aDispSelList = $this->getSelectLists();
02656             }
02657         }
02658 
02659         return $this->_aDispSelList;
02660     }
02661 
02667     public function getMoreDetailLink()
02668     {
02669         if ($this->_sMoreDetailLink == null) {
02670 
02671             // and assign special article values
02672             $this->_sMoreDetailLink = $this->getConfig()->getShopHomeURL() . 'cl=moredetails';
02673 
02674             // not always it is okey, as not all the time active category is the same as primary article cat.
02675             if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
02676                 $this->_sMoreDetailLink .= '&amp;cnid=' . $sActCat;
02677             }
02678             $this->_sMoreDetailLink .= '&amp;anid=' . $this->getId();
02679             $this->_sMoreDetailLink = $this->_sMoreDetailLink;
02680         }
02681 
02682         return $this->_sMoreDetailLink;
02683     }
02684 
02690     public function getToBasketLink()
02691     {
02692         if ($this->_sToBasketLink == null) {
02693             $myConfig = $this->getConfig();
02694 
02695             if (oxRegistry::getUtils()->isSearchEngine()) {
02696                 $this->_sToBasketLink = $this->getLink();
02697             } else {
02698                 // and assign special article values
02699                 $this->_sToBasketLink = $myConfig->getShopHomeURL();
02700 
02701                 // override some classes as these should never showup
02702                 $sActClass = oxRegistry::getConfig()->getRequestParameter('cl');
02703                 if ($sActClass == 'thankyou') {
02704                     $sActClass = 'basket';
02705                 }
02706                 $this->_sToBasketLink .= 'cl=' . $sActClass;
02707 
02708                 // this is not very correct
02709                 if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
02710                     $this->_sToBasketLink .= '&amp;cnid=' . $sActCat;
02711                 }
02712 
02713                 $this->_sToBasketLink .= '&amp;fnc=tobasket&amp;aid=' . $this->getId() . '&amp;anid=' . $this->getId();
02714 
02715                 if ($sTpl = basename(oxRegistry::getConfig()->getRequestParameter('tpl'))) {
02716                     $this->_sToBasketLink .= '&amp;tpl=' . $sTpl;
02717                 }
02718             }
02719         }
02720 
02721         return $this->_sToBasketLink;
02722     }
02723 
02729     public function getStockStatus()
02730     {
02731         return $this->_iStockStatus;
02732     }
02733 
02739     public function getDeliveryDate()
02740     {
02741         if ($this->oxarticles__oxdelivery->value != '0000-00-00') {
02742             return oxRegistry::get("oxUtilsDate")->formatDBDate($this->oxarticles__oxdelivery->value);
02743         }
02744 
02745         return false;
02746     }
02747 
02755     public function getFTPrice()
02756     {
02757         // module
02758         if ($oPrice = $this->getTPrice()) {
02759             if ($dPrice = $this->_getPriceForView($oPrice)) {
02760                 return oxRegistry::getLang()->formatCurrency($dPrice);
02761             }
02762         }
02763     }
02764 
02772     public function getFPrice()
02773     {
02774         if ($oPrice = $this->getPrice()) {
02775             $dPrice = $this->_getPriceForView($oPrice);
02776 
02777             return oxRegistry::getLang()->formatCurrency($dPrice);
02778         }
02779     }
02780 
02785     public function resetRemindStatus()
02786     {
02787         if ($this->oxarticles__oxremindactive->value == 2 &&
02788             $this->oxarticles__oxremindamount->value <= $this->oxarticles__oxstock->value
02789         ) {
02790             $this->oxarticles__oxremindactive->value = 1;
02791         }
02792     }
02793 
02801     public function getFNetPrice()
02802     {
02803         if ($oPrice = $this->getPrice()) {
02804             return oxRegistry::getLang()->formatCurrency($oPrice->getNettoPrice());
02805         }
02806     }
02807 
02813     public function isParentNotBuyable()
02814     {
02815         return $this->_blNotBuyableParent;
02816     }
02817 
02823     public function isNotBuyable()
02824     {
02825         return $this->_blNotBuyable;
02826     }
02827 
02833     public function setBuyableState($blBuyable = false)
02834     {
02835         $this->_blNotBuyable = !$blBuyable;
02836     }
02837 
02843     public function setSelectlist($aSelList)
02844     {
02845         $this->_aDispSelList = $aSelList;
02846     }
02847 
02855     public function getPictureUrl($iIndex = 1)
02856     {
02857         if ($iIndex) {
02858             $sImgName = false;
02859             if (!$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
02860                 $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
02861             }
02862 
02863             $sSize = $this->getConfig()->getConfigParam('aDetailImageSizes');
02864 
02865             return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
02866         }
02867     }
02868 
02877     public function getIconUrl($iIndex = 0)
02878     {
02879         $sImgName = false;
02880         $sDirname = "product/1/";
02881         if ($iIndex && !$this->_isFieldEmpty("oxarticles__oxpic{$iIndex}")) {
02882             $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
02883             $sDirname = "product/{$iIndex}/";
02884         } elseif (!$this->_isFieldEmpty("oxarticles__oxicon")) {
02885             $sImgName = basename($this->oxarticles__oxicon->value);
02886             $sDirname = "product/icon/";
02887         } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
02888             $sImgName = basename($this->oxarticles__oxpic1->value);
02889         }
02890 
02891         $sSize = $this->getConfig()->getConfigParam('sIconsize');
02892 
02893         $sIconUrl = oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, $iIndex);
02894 
02895         return $sIconUrl;
02896     }
02897 
02905     public function getThumbnailUrl($bSsl = null)
02906     {
02907         $sImgName = false;
02908         $sDirname = "product/1/";
02909         if (!$this->_isFieldEmpty("oxarticles__oxthumb")) {
02910             $sImgName = basename($this->oxarticles__oxthumb->value);
02911             $sDirname = "product/thumb/";
02912         } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
02913             $sImgName = basename($this->oxarticles__oxpic1->value);
02914         }
02915 
02916         $sSize = $this->getConfig()->getConfigParam('sThumbnailsize');
02917 
02918         return oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, 0, $bSsl);
02919     }
02920 
02928     public function getZoomPictureUrl($iIndex = '')
02929     {
02930         $iIndex = (int) $iIndex;
02931         if ($iIndex > 0 && !$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
02932             $sImgName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
02933             $sSize = $this->getConfig()->getConfigParam("sZoomImageSize");
02934 
02935             return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
02936         }
02937     }
02938 
02944     public function applyVats(oxPrice $oPrice)
02945     {
02946         $this->_applyVAT($oPrice, $this->getArticleVat());
02947     }
02948 
02954     public function applyDiscountsForVariant($oPrice)
02955     {
02956         // apply discounts
02957         if (!$this->skipDiscounts()) {
02958             $oDiscountList = oxRegistry::get("oxDiscountList");
02959             $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
02960 
02961             reset($aDiscounts);
02962             foreach ($aDiscounts as $oDiscount) {
02963                 $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
02964             }
02965             $oPrice->calculateDiscount();
02966         }
02967     }
02968 
02974     public function getParentArticle()
02975     {
02976         if (($sParentId = $this->oxarticles__oxparentid->value)) {
02977             $sIndex = $sParentId . "_" . $this->getLanguage();
02978             if (!isset(self::$_aLoadedParents[$sIndex])) {
02979                 self::$_aLoadedParents[$sIndex] = oxNew('oxarticle');
02980                 self::$_aLoadedParents[$sIndex]->_blLoadPrice = false;
02981                 self::$_aLoadedParents[$sIndex]->_blLoadVariants = false;
02982 
02983                 if (!self::$_aLoadedParents[$sIndex]->loadInLang($this->getLanguage(), $sParentId)) {
02984                     //return false in case parent product failed to load
02985                     self::$_aLoadedParents[$sIndex] = false;
02986                 }
02987             }
02988 
02989             return self::$_aLoadedParents[$sIndex];
02990         }
02991     }
02992 
02996     public function updateVariantsRemind()
02997     {
02998         // check if it is parent article
02999         if (!$this->isVariant() && $this->_hasAnyVariant()) {
03000             $oDb = oxDb::getDb();
03001             $sOxId = $oDb->quote($this->getId());
03002             $sOxShopId = $oDb->quote($this->getShopId());
03003             $iRemindActive = $oDb->quote($this->oxarticles__oxremindactive->value);
03004             $sUpdate = "
03005                 update oxarticles
03006                     set oxremindactive = $iRemindActive
03007                     where oxparentid = $sOxId and
03008                           oxshopid = $sOxShopId
03009             ";
03010             $oDb->execute($sUpdate);
03011         }
03012     }
03013 
03020     public function getProductId()
03021     {
03022         return $this->getId();
03023     }
03024 
03030     public function getParentId()
03031     {
03032         return $this->oxarticles__oxparentid->value;
03033     }
03034 
03040     public function isOrderArticle()
03041     {
03042         return false;
03043     }
03044 
03050     public function isVariant()
03051     {
03052         return (bool) (isset($this->oxarticles__oxparentid) ? $this->oxarticles__oxparentid->value : false);
03053     }
03054 
03060     public function isMdVariant()
03061     {
03062         $oMdVariant = oxNew("oxVariantHandler");
03063 
03064         return $oMdVariant->isMdVariant($this);
03065     }
03066 
03074     public function getSqlForPriceCategories($sFields = '')
03075     {
03076         if (!$sFields) {
03077             $sFields = 'oxid';
03078         }
03079         $sSelectWhere = "select $sFields from " . $this->_getObjectViewName('oxcategories') . " where";
03080         $sQuotedPrice = oxDb::getDb()->quote($this->oxarticles__oxprice->value);
03081 
03082         return "$sSelectWhere oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice"
03083                . " union $sSelectWhere oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice"
03084                . " union $sSelectWhere oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice";
03085     }
03086 
03094     public function inPriceCategory($sCatNid)
03095     {
03096         $oDb = oxDb::getDb();
03097 
03098         $sQuotedPrice = $oDb->quote($this->oxarticles__oxprice->value);
03099         $sQuotedCnid = $oDb->quote($sCatNid);
03100 
03101         return (bool) $oDb->getOne(
03102             "select 1 from " . $this->_getObjectViewName('oxcategories') . " where oxid=$sQuotedCnid and"
03103             . "(   (oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice)"
03104             . " or (oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice)"
03105             . " or (oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice)"
03106             . ")"
03107         );
03108     }
03109 
03115     public function getMdVariants()
03116     {
03117         if ($this->_oMdVariants) {
03118             return $this->_oMdVariants;
03119         }
03120 
03121         $oParentArticle = $this->getParentArticle();
03122         if ($oParentArticle) {
03123             $oVariants = $oParentArticle->getVariants();
03124         } else {
03125             $oVariants = $this->getVariants();
03126         }
03127 
03128         $oVariantHandler = oxNew("oxVariantHandler");
03129         $this->_oMdVariants = $oVariantHandler->buildMdVariants($oVariants, $this->getId());
03130 
03131         return $this->_oMdVariants;
03132     }
03133 
03139     public function getMdSubvariants()
03140     {
03141         return $this->getMdVariants()->getMdSubvariants();
03142     }
03143 
03152     public function getPictureFieldValue($sFieldName, $iIndex = null)
03153     {
03154         if ($sFieldName) {
03155             $sFieldName = "oxarticles__" . $sFieldName . $iIndex;
03156 
03157             return $this->$sFieldName->value;
03158         }
03159     }
03160 
03168     public function getMasterZoomPictureUrl($iIndex)
03169     {
03170         $sPicUrl = false;
03171         $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
03172 
03173         if ($sPicName && $sPicName != "nopic.jpg") {
03174             $sPicUrl = $this->getConfig()->getPictureUrl("master/product/" . $iIndex . "/" . $sPicName);
03175             if (!$sPicUrl || basename($sPicUrl) == "nopic.jpg") {
03176                 $sPicUrl = false;
03177             }
03178         }
03179 
03180         return $sPicUrl;
03181     }
03182 
03188     public function getUnitName()
03189     {
03190         if ($this->oxarticles__oxunitname->value) {
03191             return oxRegistry::getLang()->translateString($this->oxarticles__oxunitname->value);
03192         }
03193     }
03194 
03202     public function getArticleFiles($blAddFromParent = false)
03203     {
03204         if ($this->_aArticleFiles === null) {
03205 
03206             $this->_aArticleFiles = false;
03207 
03208             $sQ = "SELECT * FROM `oxfiles` WHERE `oxartid` = '" . $this->getId() . "'";
03209 
03210             if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && $blAddFromParent) {
03211                 $sQ .= " OR `oxartId` = '" . $this->oxarticles__oxparentid->value . "'";
03212             }
03213 
03214             $oArticleFiles = oxNew("oxlist");
03215             $oArticleFiles->init("oxfile");
03216             $oArticleFiles->selectString($sQ);
03217             $this->_aArticleFiles = $oArticleFiles;
03218 
03219         }
03220 
03221         return $this->_aArticleFiles;
03222     }
03223 
03229     public function isDownloadable()
03230     {
03231         return $this->oxarticles__oxisdownloadable->value;
03232     }
03233 
03239     public function hasAmountPrice()
03240     {
03241         if (self::$_blHasAmountPrice === null) {
03242 
03243             self::$_blHasAmountPrice = false;
03244 
03245             $oDb = oxDb::getDb();
03246             $sQ = "SELECT 1 FROM `oxprice2article` LIMIT 1";
03247 
03248             if ($oDb->getOne($sQ)) {
03249                 self::$_blHasAmountPrice = true;
03250             }
03251         }
03252 
03253         return self::$_blHasAmountPrice;
03254     }
03255 
03265     protected function _loadVariantList($blSimple, $blRemoveNotOrderables = true, $blForceCoreTable = null)
03266     {
03267         $oVariants = array();
03268         if (($sId = $this->getId())) {
03269             //do not load me as a parent later
03270             self::$_aLoadedParents[$sId . "_" . $this->getLanguage()] = $this;
03271 
03272             $myConfig = $this->getConfig();
03273 
03274             if (!$this->_blLoadVariants ||
03275                 (!$this->isAdmin() && !$myConfig->getConfigParam('blLoadVariants')) ||
03276                 (!$this->isAdmin() && !$this->oxarticles__oxvarcount->value)
03277             ) {
03278                 return $oVariants;
03279             }
03280 
03281             // cache
03282             $sCacheKey = $blSimple ? "simple" : "full";
03283             if ($blRemoveNotOrderables) {
03284                 if (isset($this->_aVariants[$sCacheKey])) {
03285                     return $this->_aVariants[$sCacheKey];
03286                 } else {
03287                     $this->_aVariants[$sCacheKey] = & $oVariants;
03288                 }
03289             } elseif (!$blRemoveNotOrderables) {
03290                 if (isset($this->_aVariantsWithNotOrderables[$sCacheKey])) {
03291                     return $this->_aVariantsWithNotOrderables[$sCacheKey];
03292                 } else {
03293                     $this->_aVariantsWithNotOrderables[$sCacheKey] = & $oVariants;
03294                 }
03295             }
03296 
03297             if (($this->_blHasVariants = $this->_hasAnyVariant($blForceCoreTable))) {
03298 
03299                 //load simple variants for lists
03300                 if ($blSimple) {
03301                     $oVariants = oxNew('oxsimplevariantlist');
03302                     $oVariants->setParent($this);
03303                 } else {
03304                     //loading variants
03305                     $oVariants = oxNew('oxarticlelist');
03306                     $oVariants->getBaseObject()->modifyCacheKey('_variants');
03307                 }
03308 
03309                 startProfile("selectVariants");
03310                 $blUseCoreTable = (bool) $blForceCoreTable;
03311                 $oBaseObject = $oVariants->getBaseObject();
03312                 $oBaseObject->setLanguage($this->getLanguage());
03313 
03314 
03315                 $sArticleTable = $this->getViewName($blUseCoreTable);
03316 
03317                 $sSelect = "select " . $oBaseObject->getSelectFields($blUseCoreTable) . " from $sArticleTable where " .
03318                            $this->getActiveCheckQuery($blUseCoreTable) .
03319                            $this->getVariantsQuery($blRemoveNotOrderables, $blUseCoreTable) .
03320                            " order by $sArticleTable.oxsort";
03321                 $oVariants->selectString($sSelect);
03322 
03323                 //if this is multidimensional variants, make additional processing
03324                 if ($myConfig->getConfigParam('blUseMultidimensionVariants')) {
03325                     $oMdVariants = oxNew("oxVariantHandler");
03326                     $this->_blHasMdVariants = $oMdVariants->isMdVariant($oVariants->current());
03327                 }
03328                 stopProfile("selectVariants");
03329             }
03330 
03331             //if we have variants then depending on config option the parent may be non buyable
03332             if (!$myConfig->getConfigParam('blVariantParentBuyable') && $this->_blHasVariants) {
03333                 $this->_blNotBuyableParent = true;
03334             }
03335 
03336             //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
03337             if (!$myConfig->getConfigParam('blVariantParentBuyable') && count($oVariants) == 0 && $this->_blHasVariants) {
03338                 $this->_blNotBuyable = true;
03339             }
03340         }
03341 
03342         return $oVariants;
03343     }
03344 
03353     protected function _selectCategoryIds($sSql, $sField)
03354     {
03355         $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
03356         $aResult = $oDb->getAll($sSql);
03357         $aReturn = array();
03358 
03359 
03360         foreach ($aResult as $aValue) {
03361             $aValue = array_change_key_case($aValue, CASE_LOWER);
03362 
03363 
03364             $aReturn[] = $aValue[$sField];
03365         }
03366 
03367         return $aReturn;
03368     }
03369 
03377     protected function _getCategoryIdsSelect($blActCats = false)
03378     {
03379         $sO2CView = $this->_getObjectViewName('oxobject2category');
03380         $sCatView = $this->_getObjectViewName('oxcategories');
03381 
03382         $sArticleIdSql = 'oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getId());
03383         if ($this->getParentId()) {
03384             $sArticleIdSql = '(' . $sArticleIdSql . ' or oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getParentId()) . ')';
03385         }
03386         $sActiveCategorySql = $blActCats ? $this->_getActiveCategorySelectSnippet() : '';
03387 
03388         $sSelect = "select
03389                         oxobject2category.oxcatnid as oxcatnid
03390                      from $sO2CView as oxobject2category
03391                         left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid
03392                     where $sArticleIdSql and oxcategories.oxid is not null and oxcategories.oxactive = 1 $sActiveCategorySql
03393                     order by oxobject2category.oxtime";
03394 
03395         return $sSelect;
03396     }
03397 
03403     protected function _getActiveCategorySelectSnippet()
03404     {
03405         $sCatView = $this->_getObjectViewName('oxcategories');
03406         $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 ";
03407 
03408         return $sActiveCategorySql;
03409     }
03410 
03421     protected function _getSelectCatIds($sOXID, $blActCats = false)
03422     {
03423         $sO2CView = $this->_getObjectViewName('oxobject2category');
03424         $sCatView = $this->_getObjectViewName('oxcategories');
03425         $sSelect = "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
03426         $sSelect .= 'where oxobject2category.oxobjectid=' . oxDb::getDb()->quote($sOXID) . ' and oxcategories.oxid is not null and oxcategories.oxactive = 1 ';
03427         if ($blActCats) {
03428             $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 ";
03429         }
03430         $sSelect .= 'order by oxobject2category.oxtime ';
03431 
03432         return $sSelect;
03433     }
03434 
03443     protected function _calculatePrice($oPrice, $dVat = null)
03444     {
03445         // apply VAT only if configuration requires it
03446         if (isset($dVat) || !$this->getConfig()->getConfigParam('bl_perfCalcVatOnlyForBasketOrder')) {
03447             $this->_applyVAT($oPrice, isset($dVat) ? $dVat : $this->getArticleVat());
03448         }
03449 
03450         // apply currency
03451         $this->_applyCurrency($oPrice);
03452         // apply discounts
03453         if (!$this->skipDiscounts()) {
03454             $oDiscountList = oxRegistry::get("oxDiscountList");
03455             $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
03456 
03457             reset($aDiscounts);
03458             foreach ($aDiscounts as $oDiscount) {
03459                 $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
03460             }
03461             $oPrice->calculateDiscount();
03462         }
03463 
03464         return $oPrice;
03465     }
03466 
03474     protected function _hasAnyVariant($blForceCoreTable = null)
03475     {
03476         $blHas = false;
03477         if (($sId = $this->getId())) {
03478             if ($this->oxarticles__oxshopid->value == $this->getConfig()->getShopId()) {
03479                 $blHas = (bool) $this->oxarticles__oxvarcount->value;
03480             } else {
03481                 $sArticleTable = $this->getViewName($blForceCoreTable);
03482                 $blHas = (bool) oxDb::getDb()->getOne("select 1 from $sArticleTable where oxparentid='{$sId}'");
03483             }
03484         }
03485 
03486         return $blHas;
03487     }
03488 
03494     protected function _isStockStatusChanged()
03495     {
03496         return $this->_iStockStatus != $this->_iStockStatusOnLoad;
03497     }
03498 
03504     protected function _isVisibilityChanged()
03505     {
03506         return $this->_isStockStatusChanged() && ($this->_iStockStatus == -1 || $this->_iStockStatusOnLoad == -1);
03507     }
03508 
03514     protected function _saveArtLongDesc()
03515     {
03516         $myConfig = $this->getConfig();
03517         $sShopId = $myConfig->getShopID();
03518         if (in_array("oxlongdesc", $this->_aSkipSaveFields)) {
03519             return;
03520         }
03521 
03522         if ($this->_blEmployMultilanguage) {
03523             $sValue = $this->getLongDescription()->getRawValue();
03524             if ($sValue !== null) {
03525                 $oArtExt = oxNew('oxI18n');
03526                 $oArtExt->init('oxartextends');
03527                 $oArtExt->setLanguage((int) $this->getLanguage());
03528                 if (!$oArtExt->load($this->getId())) {
03529                     $oArtExt->setId($this->getId());
03530                 }
03531                 $oArtExt->oxartextends__oxlongdesc = new oxField($sValue, oxField::T_RAW);
03532                 $oArtExt->save();
03533             }
03534         } else {
03535             $oArtExt = oxNew('oxI18n');
03536             $oArtExt->setEnableMultilang(false);
03537             $oArtExt->init('oxartextends');
03538             $aObjFields = $oArtExt->_getAllFields(true);
03539             if (!$oArtExt->load($this->getId())) {
03540                 $oArtExt->setId($this->getId());
03541             }
03542 
03543             foreach ($aObjFields as $sKey => $sValue) {
03544                 if (preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey)) {
03545                     $sField = $this->_getFieldLongName($sKey);
03546 
03547                     if (isset($this->$sField)) {
03548                         $sLongDesc = null;
03549                         if ($this->$sField instanceof oxField) {
03550                             $sLongDesc = $this->$sField->getRawValue();
03551                         } elseif (is_object($this->$sField)) {
03552                             $sLongDesc = $this->$sField->value;
03553                         }
03554                         if (isset($sLongDesc)) {
03555                             $sAEField = $oArtExt->_getFieldLongName($sKey);
03556                             $oArtExt->$sAEField = new oxField($sLongDesc, oxField::T_RAW);
03557                         }
03558                     }
03559                 }
03560             }
03561             $oArtExt->save();
03562         }
03563     }
03564 
03568     protected function _skipSaveFields()
03569     {
03570         $myConfig = $this->getConfig();
03571 
03572         $this->_aSkipSaveFields = array();
03573 
03574         $this->_aSkipSaveFields[] = 'oxtimestamp';
03575         // $this->_aSkipSaveFields[] = 'oxlongdesc';
03576         $this->_aSkipSaveFields[] = 'oxinsert';
03577         $this->_addSkippedSaveFieldsForMapping();
03578 
03579         if (!$this->_blAllowEmptyParentId && (!isset($this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '')) {
03580             $this->_aSkipSaveFields[] = 'oxparentid';
03581         }
03582 
03583     }
03584 
03594     protected function _mergeDiscounts($aDiscounts, $aItemDiscounts)
03595     {
03596         foreach ($aItemDiscounts as $sKey => $oDiscount) {
03597             // add prices of the same discounts
03598             if (array_key_exists($sKey, $aDiscounts)) {
03599                 $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
03600             } else {
03601                 $aDiscounts[$sKey] = $oDiscount;
03602             }
03603         }
03604 
03605         return $aDiscounts;
03606     }
03607 
03613     protected function _getGroupPrice()
03614     {
03615         $sPriceSufix = $this->_getUserPriceSufix();
03616         $sVarName = "oxarticles__oxprice{$sPriceSufix}";
03617         $dPrice = $this->$sVarName->value;
03618 
03619         // #1437/1436C - added config option, and check for zero A,B,C price values
03620         if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices') && (double) $dPrice == 0) {
03621             $dPrice = $this->oxarticles__oxprice->value;
03622         }
03623 
03624         return $dPrice;
03625     }
03626 
03635     protected function _getAmountPrice($dAmount = 1)
03636     {
03637         startProfile("_getAmountPrice");
03638 
03639         $dPrice = $this->_getGroupPrice();
03640         $oAmtPrices = $this->_getAmountPriceList();
03641         foreach ($oAmtPrices as $oAmPrice) {
03642             if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
03643                 && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
03644                 && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value
03645             ) {
03646                 $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
03647             }
03648         }
03649 
03650         stopProfile("_getAmountPrice");
03651 
03652         return $dPrice;
03653     }
03654 
03663     protected function _modifySelectListPrice($dPrice, $aChosenList = null)
03664     {
03665         $myConfig = $this->getConfig();
03666         // #690
03667         if ($myConfig->getConfigParam('bl_perfLoadSelectLists') && $myConfig->getConfigParam('bl_perfUseSelectlistPrice')) {
03668 
03669             $aSelLists = $this->getSelectLists();
03670 
03671             foreach ($aSelLists as $key => $aSel) {
03672                 if (isset($aChosenList[$key]) && isset($aSel[$aChosenList[$key]])) {
03673                     $oSel = $aSel[$aChosenList[$key]];
03674                     if ($oSel->priceUnit == 'abs') {
03675                         $dPrice += $oSel->price;
03676                     } elseif ($oSel->priceUnit == '%') {
03677                         $dPrice += oxPrice::percent($dPrice, $oSel->price);
03678                     }
03679                 }
03680             }
03681         }
03682 
03683         return $dPrice;
03684     }
03685 
03693     protected function _fillAmountPriceList($aAmPriceList)
03694     {
03695         $oLang = oxRegistry::getLang();
03696 
03697         // trying to find lowest price value
03698         foreach ($aAmPriceList as $sId => $oItem) {
03699 
03700             $oItemPrice = $this->_getPriceObject();
03701             if ($oItem->oxprice2article__oxaddabs->value) {
03702 
03703                 $dBasePrice = $oItem->oxprice2article__oxaddabs->value;
03704                 $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
03705 
03706                 $oItemPrice->setPrice($dBasePrice);
03707                 $this->_calculatePrice($oItemPrice);
03708 
03709             } else {
03710                 $dBasePrice = $this->_getGroupPrice();
03711                 $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
03712                 $oItemPrice->setPrice($dBasePrice);
03713                 $oItemPrice->subtractPercent($oItem->oxprice2article__oxaddperc->value);
03714             }
03715 
03716 
03717             $aAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency($this->_getPriceForView($oItemPrice));
03718         }
03719 
03720         return $aAmPriceList;
03721     }
03722 
03730     public function getVariantIds($blActiveVariants = true)
03731     {
03732         $aSelect = array();
03733         $sId = $this->getId();
03734         if ($sId) {
03735             $sActiveSqlSnippet = "";
03736             if ($blActiveVariants) {
03737                 $sActiveSqlSnippet = " and " . $this->getSqlActiveSnippet(true);
03738             }
03739             $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
03740             $sQ = "select oxid from " . $this->getViewName(true) . " where oxparentid = " . $oDb->quote($sId) .
03741                   $sActiveSqlSnippet . " order by oxsort";
03742             $oRs = $oDb->select($sQ);
03743             if ($oRs != false && $oRs->recordCount() > 0) {
03744                 while (!$oRs->EOF) {
03745                     $aSelect[] = reset($oRs->fields);
03746                     $oRs->moveNext();
03747                 }
03748             }
03749         }
03750 
03751         return $aSelect;
03752     }
03753 
03763     protected function _getVariantsIds($blActiveVariants = true)
03764     {
03765         return $this->getVariantIds($blActiveVariants);
03766     }
03767 
03773     public function getArticleVat()
03774     {
03775         if (!isset($this->_dArticleVat)) {
03776             $this->_dArticleVat = oxRegistry::get("oxVatSelector")->getArticleVat($this);
03777         }
03778 
03779         return $this->_dArticleVat;
03780     }
03781 
03788     protected function _applyVAT(oxPrice $oPrice, $dVat)
03789     {
03790         startProfile(__FUNCTION__);
03791         $oPrice->setVAT($dVat);
03792         if (($dVat = oxRegistry::get("oxVatSelector")->getArticleUserVat($this)) !== false) {
03793             $oPrice->setUserVat($dVat);
03794         }
03795         stopProfile(__FUNCTION__);
03796     }
03797 
03804     protected function _applyCurrency(oxPrice $oPrice, $oCur = null)
03805     {
03806         if (!$oCur) {
03807             $oCur = $this->getConfig()->getActShopCurrencyObject();
03808         }
03809 
03810         $oPrice->multiply($oCur->rate);
03811     }
03812 
03813 
03820     protected function _getAttribsString(&$sAttributeSql, &$iCnt)
03821     {
03822         // we do not use lists here as we don't need this overhead right now
03823         $oDb = oxDb::getDb();
03824         $sSelect = 'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid=' . $oDb->quote($this->getId());
03825         if ($this->getParentId()) {
03826             $sSelect .= ' OR oxobject2attribute.oxobjectid=' . $oDb->quote($this->getParentId());
03827         }
03828         $sAttributeSql = '';
03829         $aAttributeIds = $oDb->getCol($sSelect);
03830         if (is_array($aAttributeIds) && count($aAttributeIds)) {
03831             $aAttributeIds = array_unique($aAttributeIds);
03832             $iCnt = count($aAttributeIds);
03833             $sAttributeSql .= 't1.oxattrid IN ( ' . implode(',', $oDb->quoteArray($aAttributeIds)) . ') ';
03834         }
03835     }
03836 
03845     protected function _getSimList($sAttributeSql, $iCnt)
03846     {
03847         // #523A
03848         $iAttrPercent = $this->getConfig()->getConfigParam('iAttributesPercent') / 100;
03849         // 70% same attributes
03850         if (!$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
03851             $iAttrPercent = 0.70;
03852         }
03853         // #1137V iAttributesPercent = 100 doesn't work
03854         $iHitMin = ceil($iCnt * $iAttrPercent);
03855 
03856         $aExcludeIds = array();
03857         $aExcludeIds[] = $this->getId();
03858         if ($this->getParentId()) {
03859             $aExcludeIds[] = $this->getParentId();
03860         }
03861 
03862         // we do not use lists here as we don't need this overhead right now
03863         $sSelect = "select oxobjectid from oxobject2attribute as t1 where
03864                     ( $sAttributeSql )
03865                     and t1.oxobjectid NOT IN (" . implode(', ', oxDb::getDb()->quoteArray($aExcludeIds)) . ")
03866                     group by t1.oxobjectid having count(*) >= $iHitMin LIMIT 0, 20";
03867 
03868         return oxDb::getDb()->getCol($sSelect);
03869     }
03870 
03879     protected function _generateSimListSearchStr($sArticleTable, $aList)
03880     {
03881         $sFieldList = $this->getSelectFields();
03882         $aList = array_slice($aList, 0, $this->getConfig()->getConfigParam('iNrofSimilarArticles'));
03883 
03884         $sSearch = "select $sFieldList from $sArticleTable where " . $this->getSqlActiveSnippet() . "  and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
03885 
03886         $sSearch .= implode(',', oxdb::getDb()->quoteArray($aList)) . ')';
03887 
03888         // #524A -- randomizing articles in attribute list
03889         $sSearch .= ' order by rand() ';
03890 
03891         return $sSearch;
03892     }
03893 
03902     protected function _generateSearchStr($sOXID, $blSearchPriceCat = false)
03903     {
03904 
03905         $sCatView = getViewName('oxcategories', $this->getLanguage());
03906         $sO2CView = getViewName('oxobject2category');
03907 
03908         // we do not use lists here as we don't need this overhead right now
03909         if (!$blSearchPriceCat) {
03910             $sSelect = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
03911                          {$sCatView}.oxid = oxobject2category.oxcatnid
03912                          where oxobject2category.oxobjectid=" . oxDb::getDb()->quote($sOXID) . " and {$sCatView}.oxid is not null ";
03913         } else {
03914             $sSelect = "select {$sCatView}.* from {$sCatView} where
03915                          '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
03916                          '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
03917         }
03918 
03919         return $sSelect;
03920     }
03921 
03927     protected function _generateSearchStrForCustomerBought()
03928     {
03929         $sArtTable = $this->getViewName();
03930         $sOrderArtTable = getViewName('oxorderarticles');
03931 
03932         // fetching filter params
03933         $sIn = " '{$this->oxarticles__oxid->value}' ";
03934         if ($this->oxarticles__oxparentid->value) {
03935 
03936             // adding article parent
03937             $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
03938             $sParentIdForVariants = $this->oxarticles__oxparentid->value;
03939 
03940         } else {
03941             $sParentIdForVariants = $this->getId();
03942         }
03943 
03944         // adding variants
03945         $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
03946         $oRs = $oDb->select("select oxid from {$sArtTable} where oxparentid = " . $oDb->quote($sParentIdForVariants) . " and oxid != " . $oDb->quote($this->oxarticles__oxid->value));
03947         if ($oRs != false && $oRs->recordCount() > 0) {
03948             while (!$oRs->EOF) {
03949                 $sIn .= ", " . $oDb->quote(current($oRs->fields)) . " ";
03950                 $oRs->moveNext();
03951             }
03952         }
03953 
03954         $iLimit = (int) $this->getConfig()->getConfigParam('iNrofCustomerWhoArticles');
03955         $iLimit = $iLimit ? ($iLimit * 10) : 50;
03956 
03957         // building sql (optimized)
03958         $sQ = "select distinct {$sArtTable}.* from (
03959                    select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
03960                ) as suborder
03961                left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
03962                left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
03963                where {$sArtTable}.oxid not in ( {$sIn} )
03964                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and " . $this->getSqlActiveSnippet();
03965 
03966         /* non optimized, but could be used if index forcing is not supported
03967         // building sql
03968         $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
03969                    select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
03970                ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
03971                and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
03972                and ".$this->getSqlActiveSnippet();
03973         */
03974 
03975         return $sQ;
03976     }
03977 
03987     protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
03988     {
03989         $sCategoryView = getViewName('oxcategories');
03990         $sO2CView = getViewName('oxobject2category');
03991 
03992         $oDb = oxDb::getDb();
03993         $sOXID = $oDb->quote($sOXID);
03994         $sCatId = $oDb->quote($sCatId);
03995 
03996         if (!$dPriceFromTo) {
03997             $sSelect = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
03998             $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
03999             $sSelect .= "where oxobject2category.oxcatnid=$sCatId and oxobject2category.oxobjectid=$sOXID ";
04000             $sSelect .= "and oxcategories.oxactive = 1 order by oxobject2category.oxtime ";
04001         } else {
04002             $dPriceFromTo = $oDb->quote($dPriceFromTo);
04003             $sSelect = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
04004             $sSelect .= "oxcategories.oxid=$sCatId and $dPriceFromTo >= oxcategories.oxpricefrom and ";
04005             $sSelect .= "$dPriceFromTo <= oxcategories.oxpriceto ";
04006         }
04007 
04008         return $sSelect;
04009     }
04010 
04016     protected function _getAmountPriceList()
04017     {
04018         if ($this->_oAmountPriceList === null) {
04019             $oAmPriceList = oxNew('oxAmountPricelist');
04020 
04021             if (!$this->skipDiscounts()) {
04022                 //collecting assigned to article amount-price list
04023                 $oAmPriceList->load($this);
04024 
04025                 // prepare abs prices if currently having percentages
04026                 $oBasePrice = $this->_getGroupPrice();
04027                 foreach ($oAmPriceList as $oAmPrice) {
04028                     if ($oAmPrice->oxprice2article__oxaddperc->value) {
04029                         $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent($oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value), oxField::T_RAW);
04030                     }
04031                 }
04032 
04033             }
04034 
04035             $this->_oAmountPriceList = $oAmPriceList;
04036         }
04037 
04038         return $this->_oAmountPriceList;
04039     }
04040 
04048     protected function _isFieldEmpty($sFieldName)
04049     {
04050         $mValue = $this->$sFieldName->value;
04051 
04052         if (is_null($mValue)) {
04053             return true;
04054         }
04055 
04056         if ($mValue === '') {
04057             return true;
04058         }
04059 
04060         // certain fields with zero value treat as empty
04061         $aZeroValueFields = array('oxarticles__oxprice', 'oxarticles__oxvat', 'oxarticles__oxunitquantity');
04062 
04063         if (!$mValue && in_array($sFieldName, $aZeroValueFields)) {
04064             return true;
04065         }
04066 
04067 
04068         if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
04069             return true;
04070         }
04071 
04072         $sFieldName = strtolower($sFieldName);
04073 
04074         if ($sFieldName == 'oxarticles__oxicon' && (strpos($mValue, "nopic_ico.jpg") !== false || strpos($mValue, "nopic.jpg") !== false)) {
04075             return true;
04076         }
04077 
04078         if (strpos($mValue, "nopic.jpg") !== false && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom')) {
04079             return true;
04080         }
04081 
04082         return false;
04083     }
04084 
04092     protected function _assignParentFieldValue($sFieldName)
04093     {
04094         if (!($oParentArticle = $this->getParentArticle())) {
04095             return;
04096         }
04097 
04098         $sCopyFieldName = $this->_getFieldLongName($sFieldName);
04099 
04100         // assigning only these which parent article has
04101         if ($oParentArticle->$sCopyFieldName != null) {
04102 
04103             // only overwrite database values
04104             if (substr($sCopyFieldName, 0, 12) != 'oxarticles__') {
04105                 return;
04106             }
04107 
04108             //do not copy certain fields
04109             if (in_array($sCopyFieldName, $this->_aNonCopyParentFields)) {
04110                 return;
04111             }
04112 
04113             //skip picture parent value assignment in case master image is set for variant
04114             if ($this->_isFieldEmpty($sCopyFieldName) && $this->_isImageField($sCopyFieldName) && $this->_hasMasterImage(1)) {
04115                 return;
04116             }
04117 
04118             //COPY THE VALUE
04119             if ($this->_isFieldEmpty($sCopyFieldName)) {
04120                 $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
04121             }
04122         }
04123     }
04124 
04132     protected function _isImageField($sFieldName)
04133     {
04134         $blIsImageField = (stristr($sFieldName, '_oxthumb') || stristr($sFieldName, '_oxicon') || stristr($sFieldName, '_oxzoom') || stristr($sFieldName, '_oxpic'));
04135 
04136         return $blIsImageField;
04137     }
04138 
04142     protected function _assignParentFieldValues()
04143     {
04144         startProfile('articleAssignParentInternal');
04145         if ($this->oxarticles__oxparentid->value) {
04146             // yes, we are in fact a variant
04147             if (!$this->isAdmin() || ($this->_blLoadParentData && $this->isAdmin())) {
04148                 foreach ($this->_aFieldNames as $sFieldName => $sVal) {
04149                     $this->_assignParentFieldValue($sFieldName);
04150                 }
04151             }
04152         }
04153         stopProfile('articleAssignParentInternal');
04154     }
04155 
04159     protected function _assignNotBuyableParent()
04160     {
04161         if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') &&
04162             ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value)
04163         ) {
04164             $this->_blNotBuyableParent = true;
04165 
04166         }
04167     }
04168 
04172     protected function _assignStock()
04173     {
04174         $myConfig = $this->getConfig();
04175         // -----------------------------------
04176         // stock
04177         // -----------------------------------
04178 
04179         // #1125 A. must round (using floor()) value taken from database and cast to int
04180         if (!$myConfig->getConfigParam('blAllowUnevenAmounts') && !$this->isAdmin()) {
04181             $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
04182         }
04183         //GREEN light
04184         $this->_iStockStatus = 0;
04185 
04186         // if we have flag /*1 or*/ 4 - we show always green light
04187         if ($myConfig->getConfigParam('blUseStock') && /*$this->oxarticles__oxstockflag->value != 1 && */
04188             $this->oxarticles__oxstockflag->value != 4
04189         ) {
04190             //ORANGE light
04191             $iStock = $this->oxarticles__oxstock->value;
04192 
04193             if ($this->_blNotBuyableParent) {
04194                 $iStock = $this->oxarticles__oxvarstock->value;
04195             }
04196 
04197 
04198             if ($iStock <= $myConfig->getConfigParam('sStockWarningLimit') && $iStock > 0) {
04199                 $this->_iStockStatus = 1;
04200             }
04201 
04202             //RED light
04203             if ($iStock <= 0) {
04204                 $this->_iStockStatus = -1;
04205             }
04206         }
04207 
04208 
04209         // stock
04210         if ($myConfig->getConfigParam('blUseStock') && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
04211             $iOnStock = $this->oxarticles__oxstock->value;
04212             if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
04213                 $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
04214             }
04215             if ($iOnStock <= 0) {
04216                 $this->setBuyableState(false);
04217             }
04218         }
04219 
04220         //exceptional handling for variant parent stock:
04221         if ($this->_blNotBuyable && $this->oxarticles__oxvarstock->value) {
04222             $this->setBuyableState(true);
04223             //but then at least setting notBuaybleParent to true
04224             $this->_blNotBuyableParent = true;
04225         }
04226 
04227         //special treatment for lists when blVariantParentBuyable config option is set to false
04228         //then we just hide "to basket" button.
04229         //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
04230         if (!$myConfig->getConfigParam('blVariantParentBuyable') && !$myConfig->getConfigParam('blLoadVariants') && $this->oxarticles__oxvarstock->value) {
04231             $this->setBuyableState(false);
04232         }
04233 
04234         //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
04235         if (!$this->_blNotBuyable && $this->_blNotBuyableParent && $this->oxarticles__oxvarcount->value == 0) {
04236             $this->setBuyableState(false);
04237         }
04238     }
04239 
04243     protected function _assignPersistentParam()
04244     {
04245         // Persistent Parameter Handling
04246         $aPersParam = oxRegistry::getSession()->getVariable('persparam');
04247         if (isset($aPersParam) && isset($aPersParam[$this->getId()])) {
04248             $this->_aPersistParam = $aPersParam[$this->getId()];
04249         }
04250     }
04251 
04255     protected function _assignDynImageDir()
04256     {
04257         $myConfig = $this->getConfig();
04258 
04259         $sThisShop = $this->oxarticles__oxshopid->value;
04260 
04261         $this->_sDynImageDir = $myConfig->getPictureUrl(null, false);
04262         $this->dabsimagedir = $myConfig->getPictureDir(false); //$sThisShop
04263         $this->nossl_dimagedir = $myConfig->getPictureUrl(null, false, false, null, $sThisShop); //$sThisShop
04264         $this->ssl_dimagedir = $myConfig->getPictureUrl(null, false, true, null, $sThisShop); //$sThisShop
04265     }
04266 
04270     protected function _assignComparisonListFlag()
04271     {
04272         // #657 add a flag if article is on comparisonlist
04273 
04274         $aItems = oxRegistry::getSession()->getVariable('aFiltcompproducts');
04275         if (isset($aItems[$this->getId()])) {
04276             $this->_blIsOnComparisonList = true;
04277         }
04278     }
04279 
04287     protected function _insert()
04288     {
04289         // set oxinsert
04290         $sNow = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
04291         $this->oxarticles__oxinsert = new oxField($sNow);
04292         if (!is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
04293             $this->oxarticles__oxsubclass = new oxField('oxarticle');
04294         }
04295 
04296         $blRes = parent::_insert();
04297 
04298 
04299         return $blRes;
04300     }
04301 
04307     protected function _update()
04308     {
04309 
04310         $this->setUpdateSeo(true);
04311         $this->_setUpdateSeoOnFieldChange('oxtitle');
04312 
04313         $this->_skipSaveFields();
04314 
04315         $myConfig = $this->getConfig();
04316 
04317 
04318         $blRes = parent::_update();
04319 
04320 
04321         return $blRes;
04322     }
04323 
04331     protected function _deleteRecords($sOXID)
04332     {
04333         $oDb = oxDb::getDb();
04334 
04335         $sOXID = $oDb->quote($sOXID);
04336 
04337         //remove other records
04338         $sDelete = 'delete from oxobject2article where oxarticlenid = ' . $sOXID . ' or oxobjectid = ' . $sOXID . ' ';
04339         $oDb->execute($sDelete);
04340 
04341         $sDelete = 'delete from oxobject2attribute where oxobjectid = ' . $sOXID . ' ';
04342         $oDb->execute($sDelete);
04343 
04344         $sDelete = 'delete from oxobject2category where oxobjectid = ' . $sOXID . ' ';
04345         $oDb->execute($sDelete);
04346 
04347         $sDelete = 'delete from oxobject2selectlist where oxobjectid = ' . $sOXID . ' ';
04348         $oDb->execute($sDelete);
04349 
04350         $sDelete = 'delete from oxprice2article where oxartid = ' . $sOXID . ' ';
04351         $oDb->execute($sDelete);
04352 
04353         $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = ' . $sOXID . ' ';
04354         $oDb->execute($sDelete);
04355 
04356         $sDelete = 'delete from oxratings where oxobjectid = ' . $sOXID . ' ';
04357         $rs = $oDb->execute($sDelete);
04358 
04359         $sDelete = 'delete from oxaccessoire2article where oxobjectid = ' . $sOXID . ' or oxarticlenid = ' . $sOXID . ' ';
04360         $oDb->execute($sDelete);
04361 
04362         //#1508C - deleting oxobject2delivery entries added
04363         $sDelete = 'delete from oxobject2delivery where oxobjectid = ' . $sOXID . ' and oxtype=\'oxarticles\' ';
04364         $oDb->execute($sDelete);
04365 
04366         $sDelete = 'delete from oxartextends where oxid = ' . $sOXID . ' ';
04367         $oDb->execute($sDelete);
04368 
04369         //delete the record
04370         foreach ($this->_getLanguageSetTables("oxartextends") as $sSetTbl) {
04371             $oDb->execute("delete from $sSetTbl where oxid = {$sOXID}");
04372         }
04373 
04374         $sDelete = 'delete from oxactions2article where oxartid = ' . $sOXID . ' ';
04375         $rs = $oDb->execute($sDelete);
04376 
04377         $sDelete = 'delete from oxobject2list where oxobjectid = ' . $sOXID . ' ';
04378         $rs = $oDb->execute($sDelete);
04379 
04380 
04381         return $rs;
04382     }
04383 
04389     protected function _deleteVariantRecords($sOXID)
04390     {
04391         if ($sOXID) {
04392             $oDb = oxDb::getDb();
04393             //collect variants to remove recursively
04394             $sQ = 'select oxid from ' . $this->getViewName() . ' where oxparentid = ' . $oDb->quote($sOXID);
04395             $rs = $oDb->select($sQ, false, false);
04396             $oArticle = oxNew("oxArticle");
04397             if ($rs != false && $rs->recordCount() > 0) {
04398                 while (!$rs->EOF) {
04399                     $oArticle->setId($rs->fields[0]);
04400                     $oArticle->delete();
04401                     $rs->moveNext();
04402                 }
04403             }
04404         }
04405     }
04406 
04410     protected function _deletePics()
04411     {
04412         $myUtilsPic = oxRegistry::get("oxUtilsPic");
04413         $myConfig = $this->getConfig();
04414         $oPictureHandler = oxRegistry::get("oxPictureHandler");
04415 
04416         //deleting custom main icon
04417         $oPictureHandler->deleteMainIcon($this);
04418 
04419         //deleting custom thumbnail
04420         $oPictureHandler->deleteThumbnail($this);
04421 
04422         $sAbsDynImageDir = $myConfig->getPictureDir(false);
04423 
04424         // deleting master image and all generated images
04425         $iPicCount = $myConfig->getConfigParam('iPicCount');
04426         for ($i = 1; $i <= $iPicCount; $i++) {
04427             $oPictureHandler->deleteArticleMasterPicture($this, $i);
04428         }
04429     }
04430 
04438     protected function _onChangeResetCounts($sOxid, $sVendorId = null, $sManufacturerId = null)
04439     {
04440         $myUtilsCount = oxRegistry::get("oxUtilsCount");
04441 
04442         if ($sVendorId) {
04443             $myUtilsCount->resetVendorArticleCount($sVendorId);
04444         }
04445 
04446         if ($sManufacturerId) {
04447             $myUtilsCount->resetManufacturerArticleCount($sManufacturerId);
04448         }
04449 
04450         $aCategoryIds = $this->getCategoryIds();
04451         //also reseting category counts
04452         foreach ($aCategoryIds as $sCatId) {
04453             $myUtilsCount->resetCatArticleCount($sCatId, false);
04454         }
04455     }
04456 
04462     protected function _onChangeUpdateStock($sParentID)
04463     {
04464         if ($sParentID) {
04465             $oDb = oxDb::getDb();
04466             $sParentIdQuoted = $oDb->quote($sParentID);
04467             $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = ' . $sParentIdQuoted;
04468             $rs = $oDb->select($sQ, false, false);
04469             $iOldStock = $rs->fields[0];
04470             $iVendorID = $rs->fields[1];
04471             $iManufacturerID = $rs->fields[2];
04472 
04473             $sQ = 'select sum(oxstock) from ' . $this->getViewName(true) . ' where oxparentid = ' . $sParentIdQuoted . ' and ' . $this->getSqlActiveSnippet(true) . ' and oxstock > 0 ';
04474             $iStock = (float) $oDb->getOne($sQ, false, false);
04475 
04476             $sQ = 'update oxarticles set oxvarstock = ' . $iStock . ' where oxid = ' . $sParentIdQuoted;
04477             $oDb->execute($sQ);
04478 
04479             //now lets update category counts
04480             //first detect stock status change for this article (to or from 0)
04481             if ($iStock < 0) {
04482                 $iStock = 0;
04483             }
04484             if ($iOldStock < 0) {
04485                 $iOldStock = 0;
04486             }
04487             if ($this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock) {
04488                 //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
04489                 // so far we leave it like this but later we could move all count resets to one or two functions
04490                 $this->_onChangeResetCounts($sParentID, $iVendorID, $iManufacturerID);
04491             }
04492         }
04493     }
04494 
04500     protected function _onChangeStockResetCount($sOxid)
04501     {
04502         $myConfig = $this->getConfig();
04503 
04504         if ($myConfig->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2 &&
04505             ($this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value) <= 0
04506         ) {
04507 
04508             $this->_onChangeResetCounts($sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
04509         }
04510     }
04511 
04517     protected function _onChangeUpdateVarCount($sParentID)
04518     {
04519         if ($sParentID) {
04520             $oDb = oxDb::getDb();
04521             $sParentIdQuoted = $oDb->quote($sParentID);
04522             $sQ = "select count(*) as varcount from oxarticles where oxparentid = {$sParentIdQuoted}";
04523             $iVarCount = (int) $oDb->getOne($sQ, false, false);
04524 
04525             $sQ = "update oxarticles set oxvarcount = {$iVarCount} where oxid = {$sParentIdQuoted}";
04526             $oDb->execute($sQ);
04527         }
04528     }
04529 
04535     protected function _setVarMinMaxPrice($sParentId)
04536     {
04537         if ($sParentId) {
04538             $oDb = oxDb::getDb(oxDb::FETCH_MODE_ASSOC);
04539             $sQ = '
04540                 SELECT
04541                     MIN( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varminprice`,
04542                     MAX( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varmaxprice`
04543                 FROM ' . $this->getViewName(true) . ' AS `oxarticles`
04544                     LEFT JOIN ' . $this->getViewName(true) . ' AS `p` ON ( `p`.`oxid` = `oxarticles`.`oxparentid` AND `p`.`oxprice` > 0 )
04545                 WHERE ' . $this->getSqlActiveSnippet(true) . '
04546                     AND ( `oxarticles`.`oxparentid` = ' . $oDb->quote($sParentId) . ' )';
04547             $oDb->setFetchMode(oxDb::FETCH_MODE_ASSOC);
04548             $aPrices = $oDb->getRow($sQ, false, false);
04549             if (!is_null($aPrices['varminprice']) || !is_null($aPrices['varmaxprice'])) {
04550                 $sQ = '
04551                     UPDATE `oxarticles`
04552                     SET
04553                         `oxvarminprice` = ' . $oDb->quote($aPrices['varminprice']) . ',
04554                         `oxvarmaxprice` = ' . $oDb->quote($aPrices['varmaxprice']) . '
04555                     WHERE
04556                         `oxid` = ' . $oDb->quote($sParentId);
04557             } else {
04558                 $sQ = '
04559                     UPDATE `oxarticles`
04560                     SET
04561                         `oxvarminprice` = `oxprice`,
04562                         `oxvarmaxprice` = `oxprice`
04563                     WHERE
04564                         `oxid` = ' . $oDb->quote($sParentId);
04565             }
04566             $oDb->execute($sQ);
04567         }
04568     }
04569 
04577     protected function _hasMasterImage($iIndex)
04578     {
04579         $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
04580 
04581         if ($sPicName == "nopic.jpg" || $sPicName == "") {
04582             return false;
04583         }
04584         if ($this->isVariant() &&
04585             $this->getParentArticle() &&
04586             $this->getParentArticle()->{"oxarticles__oxpic" . $iIndex}->value == $this->{"oxarticles__oxpic" . $iIndex}->value
04587         ) {
04588             return false;
04589         }
04590 
04591         $sMasterPic = 'product/' . $iIndex . "/" . $sPicName;
04592 
04593         if ($this->getConfig()->getMasterPicturePath($sMasterPic)) {
04594             return true;
04595         }
04596 
04597         return false;
04598     }
04599 
04605     protected function _isPriceViewModeNetto()
04606     {
04607         $blResult = (bool) $this->getConfig()->getConfigParam('blShowNetPrice');
04608         $oUser = $this->getArticleUser();
04609         if ($oUser) {
04610             $blResult = $oUser->isPriceViewModeNetto();
04611         }
04612 
04613         return $blResult;
04614     }
04615 
04616 
04624     protected function _getPriceObject($blCalculationModeNetto = null)
04625     {
04626         $oPrice = oxNew('oxPrice');
04627 
04628         if ($blCalculationModeNetto === null) {
04629             $blCalculationModeNetto = $this->_isPriceViewModeNetto();
04630         }
04631 
04632         if ($blCalculationModeNetto) {
04633             $oPrice->setNettoPriceMode();
04634         } else {
04635             $oPrice->setBruttoPriceMode();
04636         }
04637 
04638         return $oPrice;
04639     }
04640 
04641 
04649     protected function _getPriceForView($oPrice)
04650     {
04651         if ($this->_isPriceViewModeNetto()) {
04652             $dPrice = $oPrice->getNettoPrice();
04653         } else {
04654             $dPrice = $oPrice->getBruttoPrice();
04655         }
04656 
04657         return $dPrice;
04658     }
04659 
04660 
04670     protected function _preparePrice($dPrice, $dVat, $blCalculationModeNetto = null)
04671     {
04672         if ($blCalculationModeNetto === null) {
04673             $blCalculationModeNetto = $this->_isPriceViewModeNetto();
04674         }
04675 
04676         $oCurrency = $this->getConfig()->getActShopCurrencyObject();
04677 
04678         $blEnterNetPrice = $this->getConfig()->getConfigParam('blEnterNetPrice');
04679         if ($blCalculationModeNetto && !$blEnterNetPrice) {
04680             $dPrice = round(oxPrice::brutto2Netto($dPrice, $dVat), $oCurrency->decimal);
04681         } elseif (!$blCalculationModeNetto && $blEnterNetPrice) {
04682             $dPrice = round(oxPrice::netto2Brutto($dPrice, $dVat), $oCurrency->decimal);
04683         }
04684 
04685         return $dPrice;
04686     }
04687 
04693     protected function _getUserPriceSufix()
04694     {
04695         $sPriceSuffix = '';
04696         $oUser = $this->getArticleUser();
04697 
04698         if ($oUser) {
04699             if ($oUser->inGroup('oxidpricea')) {
04700                 $sPriceSuffix = 'a';
04701             } elseif ($oUser->inGroup('oxidpriceb')) {
04702                 $sPriceSuffix = 'b';
04703             } elseif ($oUser->inGroup('oxidpricec')) {
04704                 $sPriceSuffix = 'c';
04705             }
04706         }
04707 
04708         return $sPriceSuffix;
04709     }
04710 
04711 
04717     protected function _getPrice()
04718     {
04719         $sPriceSuffix = $this->_getUserPriceSufix();
04720         if ($sPriceSuffix === '') {
04721             $dPrice = $this->oxarticles__oxprice->value;
04722         } else {
04723             if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04724                 $dPrice = ($this->{oxarticles__oxprice . $sPriceSuffix}->value != 0) ? $this->{oxarticles__oxprice . $sPriceSuffix}->value : $this->oxarticles__oxprice->value;
04725             } else {
04726                 $dPrice = $this->{oxarticles__oxprice . $sPriceSuffix}->value;
04727             }
04728         }
04729 
04730         return $dPrice;
04731     }
04732 
04733 
04739     protected function _getVarMinPrice()
04740     {
04741         if ($this->_dVarMinPrice === null) {
04742             $dPrice = null;
04743 
04744 
04745             if (is_null($dPrice)) {
04746                 $sPriceSuffix = $this->_getUserPriceSufix();
04747                 if ($sPriceSuffix === '') {
04748                     $dPrice = $this->oxarticles__oxvarminprice->value;
04749                 } else {
04750                     $sSql = 'SELECT ';
04751                     if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04752                         $sSql .= 'MIN( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varminprice` ';
04753                     } else {
04754                         $sSql .= 'MIN(`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
04755                     }
04756 
04757                     $sSql .= ' FROM ' . $this->getViewName(true) . '
04758                     WHERE ' . $this->getSqlActiveSnippet(true) . '
04759                         AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
04760 
04761                     $dPrice = oxDb::getDb()->getOne($sSql);
04762                 }
04763             }
04764 
04765             $this->_dVarMinPrice = $dPrice;
04766         }
04767 
04768         return $this->_dVarMinPrice;
04769     }
04770 
04776     protected function _getSubShopVarMinPrice()
04777     {
04778         $myConfig = $this->getConfig();
04779         $sShopId = $myConfig->getShopId();
04780         if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
04781             $sPriceSuffix = $this->_getUserPriceSufix();
04782             $sSql = 'SELECT ';
04783             if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04784                 $sSql .= 'MIN(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varminprice` ';
04785             } else {
04786                 $sSql .= 'MIN(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
04787             }
04788             $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
04789                         INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
04790                         WHERE ' . $this->getSqlActiveSnippet(true) . '
04791                             AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
04792                             AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
04793             $dPrice = oxDb::getDb()->getOne($sSql);
04794         }
04795 
04796         return $dPrice;
04797     }
04798 
04804     protected function _getVarMaxPrice()
04805     {
04806         if ($this->_dVarMaxPrice === null) {
04807 
04808             $dPrice = null;
04809 
04810             if (is_null($dPrice)) {
04811                 $sPriceSuffix = $this->_getUserPriceSufix();
04812                 if ($sPriceSuffix === '') {
04813                     $dPrice = $this->oxarticles__oxvarmaxprice->value;
04814                 } else {
04815                     $sSql = 'SELECT ';
04816                     if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04817                         $sSql .= 'MAX( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varmaxprice` ';
04818                     } else {
04819                         $sSql .= 'MAX(`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
04820                     }
04821 
04822                     $sSql .= ' FROM ' . $this->getViewName(true) . '
04823                         WHERE ' . $this->getSqlActiveSnippet(true) . '
04824                             AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
04825 
04826                     $dPrice = oxDb::getDb()->getOne($sSql);
04827                 }
04828             }
04829 
04830             $this->_dVarMaxPrice = $dPrice;
04831         }
04832 
04833         return $this->_dVarMaxPrice;
04834     }
04835 
04841     protected function _getSubShopVarMaxPrice()
04842     {
04843         $myConfig = $this->getConfig();
04844         $sShopId = $myConfig->getShopId();
04845         if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
04846             $sPriceSuffix = $this->_getUserPriceSufix();
04847             $sSql = 'SELECT ';
04848             if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
04849                 $sSql .= 'MAX(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varmaxprice` ';
04850             } else {
04851                 $sSql .= 'MAX(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
04852             }
04853             $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
04854                         INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
04855                         WHERE ' . $this->getSqlActiveSnippet(true) . '
04856                             AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
04857                             AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
04858             $dPrice = oxDb::getDb()->getOne($sSql);
04859         }
04860 
04861         return $dPrice;
04862     }
04863 
04871     protected function _loadFromDb($sOXID)
04872     {
04873 
04874         $sSelect = $this->buildSelectString(array($this->getViewName() . ".oxid" => $sOXID));
04875 
04876 
04877         $aData = oxDb::getDb(oxDb::FETCH_MODE_ASSOC)->getRow($sSelect);
04878 
04879         return $aData;
04880     }
04881 
04887     protected function _updateParentDependFields()
04888     {
04889         $oDb = oxDb::getDb();
04890 
04891         foreach ($this->_getCopyParentFields() as $sField) {
04892             $sValue = isset($this->$sField->value) ? $this->$sField->value : 0;
04893             $sSqlSets[] = '`' . str_replace('oxarticles__', '', $sField) . '` = ' . $oDb->quote($sValue);
04894         }
04895 
04896         $sSql = "UPDATE `oxarticles` SET ";
04897         $sSql .= implode(', ', $sSqlSets) . '';
04898         $sSql .= " WHERE `oxparentid` = " . $oDb->quote($this->getId());
04899 
04900         return $oDb->execute($sSql);
04901     }
04902 
04903 
04909     protected function _getCopyParentFields()
04910     {
04911         return $this->_aCopyParentField;
04912     }
04913 
04917     protected function _assignParentDependFields()
04918     {
04919         $sParent = $this->getParentArticle();
04920         if ($sParent) {
04921             foreach ($this->_getCopyParentFields() as $sField) {
04922                 $this->$sField = new oxField($sParent->$sField->value);
04923             }
04924         }
04925     }
04926 
04927 
04928 
04932     protected function _saveSortingFieldValuesOnLoad()
04933     {
04934         $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
04935         $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
04936 
04937         foreach ($aSortingFields as $sField) {
04938             $sFullField = $this->_getFieldLongName($sField);
04939             $this->_aSortingFieldsOnLoad[$sFullField] = $this->$sFullField->value;
04940         }
04941     }
04942 }