OXID eShop CE  4.10.1
 All Classes Namespaces Files Functions Variables Pages
oxarticle.php
Go to the documentation of this file.
1 <?php
2 
3 // defining supported link types
4 define('OXARTICLE_LINKTYPE_CATEGORY', 0);
5 define('OXARTICLE_LINKTYPE_VENDOR', 1);
6 define('OXARTICLE_LINKTYPE_MANUFACTURER', 2);
7 define('OXARTICLE_LINKTYPE_PRICECATEGORY', 3);
8 define('OXARTICLE_LINKTYPE_TAG', 4);
9 // @deprecated since v5.3 (2016-06-17); Listmania will be moved to an own module.
10 define('OXARTICLE_LINKTYPE_RECOMM', 5);
11 // END deprecated
12 
19 class oxArticle extends oxI18n implements oxIArticle, oxIUrl
20 {
21 
22 
28  protected $_sClassName = 'oxarticle';
29 
35  protected $_blUseLazyLoading = true;
36 
42  protected $_sItemKey;
43 
50  protected $_blCalcPrice = true;
51 
57  protected $_oPrice = null;
58 
59 
65  protected $_dVarMinPrice = null;
66 
72  protected $_dVarMaxPrice = null;
73 
79  protected $_dArticleVat = null;
80 
86  protected $_aPersistParam = null;
87 
93  protected $_blNotBuyable = false;
94 
101  protected $_blLoadVariants = true;
102 
108  protected $_aVariants = null;
109 
116 
125  protected $_blNotBuyableParent = false;
126 
127 
131  protected $_blHasVariants = false;
132 
136  protected $_blHasMdVariants = false;
137 
143  protected $_blIsOnComparisonList = false;
144 
150  protected $_oUser = null;
151 
158  protected $_blLoadPrice = true;
159 
166  protected $_fPricePerUnit = null;
167 
171  protected $_blLoadParentData = false;
172 
176  protected $_blAllowEmptyParentId = false;
177 
181  protected $_blSkipAssign = false;
182 
188  protected $_blSkipDiscounts = null;
189 
194  protected $_oAttributeList = null;
195 
196 
202  protected $_blIsRangePrice = null;
203 
209  protected $_aMediaUrls = null;
210 
216  static protected $_aLoadedParents;
217 
223  static protected $_aSelList;
224 
230  protected $_aDispSelList;
231 
237  protected $_blIsSeoObject = true;
238 
244  protected $_oAmountPriceList = null;
245 
254  protected $_iLinkType = 0;
255 
261  protected $_aStdUrls = array();
262 
268  protected $_aSeoUrls = array();
269 
275  protected $_aSeoAddParams = array();
276 
282  protected $_aStdAddParams = array();
283 
289  protected $_sDynImageDir = null;
290 
296  protected $_sMoreDetailLink = null;
297 
303  protected $_sToBasketLink = null;
304 
310  protected $_iStockStatusOnLoad = null;
311 
317  protected $_aSortingFieldsOnLoad = array();
318 
324  protected $_iStockStatus = null;
325 
331  protected $_oTPrice = null;
332 
338  protected $_oAmountPriceInfo = null;
339 
345  protected $_dAmountPrice = null;
346 
352  protected static $_aArticleManufacturers = array();
353 
359  protected static $_aArticleVendors = array();
360 
366  protected static $_aArticleCats = array();
367 
373  protected $_aNonCopyParentFields = array('oxarticles__oxinsert',
374  'oxarticles__oxtimestamp',
375  'oxarticles__oxnid',
376  'oxarticles__oxid',
377  'oxarticles__oxparentid');
378 
384  protected $_aCopyParentField = array('oxarticles__oxnonmaterial',
385  'oxarticles__oxfreeshipping',
386  'oxarticles__oxisdownloadable',
387  'oxarticles__oxshowcustomagreement');
388 
394  protected $_oMdVariants = null;
395 
401  protected $_oLongDesc = null;
402 
410  protected $_aVariantSelections = array();
411 
417  protected static $_aSelections = array();
418 
424  protected static $_aCategoryCache = null;
425 
431  protected static $_blHasAmountPrice = null;
432 
438  protected $_aArticleFiles = null;
439 
445  protected $_blCanUpdateAnyField = null;
446 
455  public function __construct($aParams = null)
456  {
457  if ($aParams && is_array($aParams)) {
458  foreach ($aParams as $sParam => $mValue) {
459  $this->$sParam = $mValue;
460  }
461  }
463  $this->init('oxarticles');
464  }
465 
474  public function __get($sName)
475  {
476  $this->$sName = parent::__get($sName);
477  if ($this->$sName) {
478  // since the field could have been loaded via lazy loading
479  $this->_assignParentFieldValue($sName);
480  }
481 
482  return $this->$sName;
483  }
484 
491  public function __set($sName, $sValue)
492  {
493  parent::__set($sName, $sValue);
494  }
495 
502  public function isInList()
503  {
504  return $this->_isInList();
505  }
506 
514  public function setId($sId = null)
515  {
516  $sId = parent::setId($sId);
517 
518  // TODO: in oxbase::setId make it to check if exists and update, not recreate, then delete this overload
519  $this->oxarticles__oxnid = $this->oxarticles__oxid;
520 
521  return $sId;
522  }
523 
533  public function getActiveCheckQuery($blForceCoreTable = null)
534  {
535  $sTable = $this->getViewName($blForceCoreTable);
536 
537  // check if article is still active
538  $sQ = " $sTable.oxactive = 1 ";
539 
540  // enabled time range check ?
541  if ($this->getConfig()->getConfigParam('blUseTimeCheck')) {
542  $sDate = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
543  $sQ = "( $sQ or ( $sTable.oxactivefrom < '$sDate' and $sTable.oxactiveto > '$sDate' ) ) ";
544  }
545 
546  return $sQ;
547  }
548 
562  public function getStockCheckQuery($blForceCoreTable = null)
563  {
564  $myConfig = $this->getConfig();
565  $sTable = $this->getViewName($blForceCoreTable);
566 
567  $sQ = "";
568 
569  //do not check for variants
570  if ($myConfig->getConfigParam('blUseStock')) {
571  $sQ = " and ( $sTable.oxstockflag != 2 or ( $sTable.oxstock + $sTable.oxvarstock ) > 0 ) ";
572  //V #M513: When Parent article is not purchasable, it's visibility should be displayed in shop only if any of Variants is available.
573  if (!$myConfig->getConfigParam('blVariantParentBuyable')) {
574  $sTimeCheckQ = '';
575  if ($myConfig->getConfigParam('blUseTimeCheck')) {
576  $sDate = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
577  $sTimeCheckQ = " or ( art.oxactivefrom < '$sDate' and art.oxactiveto > '$sDate' )";
578  }
579  $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 ) ) ";
580  }
581  }
582 
583  return $sQ;
584  }
585 
597  public function getVariantsQuery($blRemoveNotOrderables, $blForceCoreTable = null)
598  {
599  $sTable = $this->getViewName($blForceCoreTable);
600  $sQ = " and $sTable.oxparentid = '" . $this->getId() . "' ";
601 
602  //checking if variant is active and stock status
603  if ($this->getConfig()->getConfigParam('blUseStock')) {
604  $sQ .= " and ( $sTable.oxstock > 0 or ( $sTable.oxstock <= 0 and $sTable.oxstockflag != 2 ";
605  if ($blRemoveNotOrderables) {
606  $sQ .= " and $sTable.oxstockflag != 3 ";
607  }
608  $sQ .= " ) ) ";
609  }
610 
611  return $sQ;
612  }
613 
619  public function getUnitQuantity()
620  {
621  return $this->oxarticles__oxunitquantity->value;
622  }
623 
629  public function getSize()
630  {
631  $dSize = $this->oxarticles__oxlength->value *
632  $this->oxarticles__oxwidth->value *
633  $this->oxarticles__oxheight->value;
634 
635  return $dSize;
636  }
637 
643  public function getWeight()
644  {
645  return $this->oxarticles__oxweight->value;
646  }
647 
655  public function getSqlActiveSnippet($blForceCoreTable = null)
656  {
657  // check if article is still active
658  $sQ = $this->getActiveCheckQuery($blForceCoreTable);
659 
660  // stock and variants check
661  $sQ .= $this->getStockCheckQuery($blForceCoreTable);
662 
663 
664  return "( $sQ ) ";
665  }
666 
672  public function setSkipAssign($blSkipAssign)
673  {
674  $this->_blSkipAssign = $blSkipAssign;
675  }
676 
680  public function disablePriceLoad()
681  {
682  $this->_blLoadPrice = false;
683  }
684 
688  public function enablePriceLoad()
689  {
690  $this->_blLoadPrice = true;
691  }
692 
698  public function getItemKey()
699  {
700  return $this->_sItemKey;
701  }
702 
708  public function setItemKey($sItemKey)
709  {
710  $this->_sItemKey = $sItemKey;
711  }
712 
718  public function setNoVariantLoading($blLoadVariants)
719  {
720  $this->_blLoadVariants = !$blLoadVariants;
721  }
722 
728  public function isBuyable()
729  {
730  if ($this->_blNotBuyableParent) {
731  return false;
732  }
733 
734  return !$this->_blNotBuyable;
735  }
736 
742  public function getPersParams()
743  {
744  return $this->_aPersistParam;
745  }
746 
752  public function isOnComparisonList()
753  {
755  }
756 
762  public function setOnComparisonList($blOnList)
763  {
764  $this->_blIsOnComparisonList = $blOnList;
765  }
766 
772  public function setLoadParentData($blLoadParentData)
773  {
774  $this->_blLoadParentData = $blLoadParentData;
775  }
776 
782  public function getLoadParentData()
783  {
785  }
786 
787 
795  public function isMultilingualField($sFieldName)
796  {
797  switch ($sFieldName) {
798  case "oxlongdesc":
799  // @deprecated v5.3 (2016-05-04); Tags will be moved to own module.
800  case "oxtags":
801  // END deprecated
802  return true;
803  }
804 
805  return parent::isMultilingualField($sFieldName);
806  }
807 
814  public function getFUnitPrice()
815  {
816  if ($this->_fPricePerUnit == null) {
817  if ($oPrice = $this->getUnitPrice()) {
818  if ($dPrice = $this->_getPriceForView($oPrice)) {
819  $this->_fPricePerUnit = oxRegistry::getLang()->formatCurrency($dPrice);
820  }
821  }
822  }
823 
824  return $this->_fPricePerUnit;
825  }
826 
832  public function getUnitPrice()
833  {
834  // Performance
835  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
836  return;
837  }
838 
839  $oPrice = null;
840  if ((double) $this->getUnitQuantity() && $this->oxarticles__oxunitname->value) {
841  $oPrice = clone $this->getPrice();
842  $oPrice->divide((double) $this->getUnitQuantity());
843  }
844 
845  return $oPrice;
846  }
847 
855  public function getFMinPrice()
856  {
857  $sPrice = '';
858  if ($oPrice = $this->getMinPrice()) {
859  $dPrice = $this->_getPriceForView($oPrice);
860  $sPrice = oxRegistry::getLang()->formatCurrency($dPrice);
861  }
862 
863  return $sPrice;
864  }
865 
873  public function getFVarMinPrice()
874  {
875  $sPrice = '';
876  if ($oPrice = $this->getVarMinPrice()) {
877  $dPrice = $this->_getPriceForView($oPrice);
878  $sPrice = oxRegistry::getLang()->formatCurrency($dPrice);
879  }
880 
881  return $sPrice;
882  }
883 
889  public function getVarMinPrice()
890  {
891  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
892  return;
893  }
894 
895  $oPrice = null;
896  $dPrice = $this->_getVarMinPrice();
897 
898  $dPrice = $this->_preparePrice($dPrice, $this->getArticleVat());
899 
900 
901  $oPrice = $this->_getPriceObject();
902  $oPrice->setPrice($dPrice);
903  $this->_calculatePrice($oPrice);
904 
905 
906  return $oPrice;
907  }
908 
914  public function getMinPrice()
915  {
916  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
917  return;
918  }
919 
920  $oPrice = null;
921  $dPrice = $this->_getPrice();
922  if ($this->_getVarMinPrice() !== null && $dPrice > $this->_getVarMinPrice()) {
923  $dPrice = $this->_getVarMinPrice();
924  }
925 
926  $dPrice = $this->_preparePrice($dPrice, $this->getArticleVat());
927 
928 
929  $oPrice = $this->_getPriceObject();
930  $oPrice->setPrice($dPrice);
931  $this->_calculatePrice($oPrice);
932 
933  return $oPrice;
934  }
935 
941  public function isRangePrice()
942  {
943  if ($this->_blIsRangePrice === null) {
944 
945  $this->setRangePrice(false);
946 
947  if ($this->_hasAnyVariant()) {
948  $dPrice = $this->_getPrice();
949  $dMinPrice = $this->_getVarMinPrice();
950  $dMaxPrice = $this->_getVarMaxPrice();
951 
952  if ($dMinPrice != $dMaxPrice) {
953  $this->setRangePrice();
954  } elseif (!$this->isParentNotBuyable() && $dMinPrice != $dPrice) {
955  $this->setRangePrice();
956  }
957  }
958  }
959 
960  return $this->_blIsRangePrice;
961  }
962 
963 
971  public function setRangePrice($blIsRangePrice = true)
972  {
973  return $this->_blIsRangePrice = $blIsRangePrice;
974  }
975 
981  public function isVisible()
982  {
983 
984  // admin preview mode
985  if (($blCanPreview = oxRegistry::getUtils()->canPreview()) !== null) {
986  return $blCanPreview;
987  }
988 
989  // active ?
990  $sNow = date('Y-m-d H:i:s');
991  if (!$this->oxarticles__oxactive->value &&
992  ($this->oxarticles__oxactivefrom->value > $sNow ||
993  $this->oxarticles__oxactiveto->value < $sNow
994  )
995  ) {
996  return false;
997  }
998 
999  // stock flags
1000  if ($this->getConfig()->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2) {
1001  $iOnStock = $this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value;
1002  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
1003  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
1004  }
1005  if ($iOnStock <= 0) {
1006  return false;
1007  }
1008  }
1009 
1010  return true;
1011  }
1012 
1021  public function assign($aRecord)
1022  {
1023  startProfile('articleAssign');
1024 
1025  // load object from database
1026  parent::assign($aRecord);
1027 
1028  $this->oxarticles__oxnid = $this->oxarticles__oxid;
1029 
1030  // check for simple article.
1031  if ($this->_blSkipAssign) {
1032  return;
1033  }
1034 
1035  $this->_assignParentFieldValues();
1036  $this->_assignNotBuyableParent();
1037 
1038 
1039  $this->_assignStock();
1040  $this->_assignPersistentParam();
1041  $this->_assignDynImageDir();
1042  $this->_assignComparisonListFlag();
1043 
1044 
1045  stopProfile('articleAssign');
1046  }
1047 
1048 
1059  public function load($sOXID)
1060  {
1061  // A. #1325 resetting to avoid problems when reloading (details etc)
1062  $this->_blNotBuyableParent = false;
1063 
1064 
1065  $aData = $this->_loadFromDb($sOXID);
1066 
1067  if ($aData) {
1068  $this->assign($aData);
1069 
1071 
1072  $this->_iStockStatusOnLoad = $this->_iStockStatus;
1073 
1074  $this->_isLoaded = true;
1075 
1076  return true;
1077  }
1078 
1079  return false;
1080  }
1081 
1087  public function hasSortingFieldsChanged()
1088  {
1089  $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
1090  $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
1091  $blChanged = false;
1092  foreach ($aSortingFields as $sField) {
1093  $sParameterName = 'oxarticles__' . $sField;
1094  if ($this->$sParameterName->value !== $this->_aSortingFieldsOnLoad[$sParameterName]) {
1095  $blChanged = true;
1096  break;
1097  }
1098  }
1099 
1100  return $blChanged;
1101  }
1102 
1103 
1109  public function addToRatingAverage($iRating)
1110  {
1111  $dOldRating = $this->oxarticles__oxrating->value;
1112  $dOldCnt = $this->oxarticles__oxratingcnt->value;
1113  $this->oxarticles__oxrating->setValue(($dOldRating * $dOldCnt + $iRating) / ($dOldCnt + 1));
1114  $this->oxarticles__oxratingcnt->setValue($dOldCnt + 1);
1115  $dRating = ($dOldRating * $dOldCnt + $iRating) / ($dOldCnt + 1);
1116  $dRatingCnt = (int) ($dOldCnt + 1);
1117  // oxarticles.oxtimestamp = oxarticles.oxtimestamp to keep old timestamp value
1118  $oDb = oxDb::getDb();
1119  $oDb->execute('update oxarticles set oxarticles.oxrating = ' . $dRating . ',oxarticles.oxratingcnt = ' . $dRatingCnt . ', oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = ' . $oDb->quote($this->getId()));
1120 
1121  }
1122 
1128  public function setRatingAverage($iRating)
1129  {
1130  $this->oxarticles__oxrating = new oxField($iRating);
1131  }
1132 
1138  public function setRatingCount($iRatingCnt)
1139  {
1140  $this->oxarticles__oxratingcnt = new oxField($iRatingCnt);
1141  }
1142 
1150  public function getArticleRatingAverage($blIncludeVariants = false)
1151  {
1152  if (!$blIncludeVariants) {
1153  return round($this->oxarticles__oxrating->value, 1);
1154  } else {
1155  $oRating = oxNew('oxRating');
1156 
1157  return $oRating->getRatingAverage($this->getId(), 'oxarticle', $this->_getVariantsIds());
1158  }
1159  }
1160 
1168  public function getArticleRatingCount($blIncludeVariants = false)
1169  {
1170  if (!$blIncludeVariants) {
1171  return $this->oxarticles__oxratingcnt->value;
1172  } else {
1173  $oRating = oxNew('oxRating');
1174 
1175  return $oRating->getRatingCount($this->getId(), 'oxarticle', $this->_getVariantsIds());
1176  }
1177  }
1178 
1179 
1185  public function getReviews()
1186  {
1187  $aIds = array($this->getId());
1188 
1189  if ($this->oxarticles__oxparentid->value) {
1190  $aIds[] = $this->oxarticles__oxparentid->value;
1191  }
1192 
1193  // showing variant reviews ..
1194  if ($this->getConfig()->getConfigParam('blShowVariantReviews')) {
1195  $aAdd = $this->_getVariantsIds();
1196  if (is_array($aAdd)) {
1197  $aIds = array_merge($aIds, $aAdd);
1198  }
1199  }
1200 
1201  $oReview = oxNew('oxreview');
1202  $oRevs = $oReview->loadList('oxarticle', $aIds);
1203 
1204  //if no review found, return null
1205  if ($oRevs->count() < 1) {
1206  return null;
1207  }
1208 
1209  return $oRevs;
1210  }
1211 
1217  public function getCrossSelling()
1218  {
1219  $oCrosslist = oxNew("oxarticlelist");
1220  $oCrosslist->loadArticleCrossSell($this->oxarticles__oxid->value);
1221  if ($oCrosslist->count()) {
1222  return $oCrosslist;
1223  }
1224  }
1225 
1231  public function getAccessoires()
1232  {
1233  $myConfig = $this->getConfig();
1234 
1235  // Performance
1236  if (!$myConfig->getConfigParam('bl_perfLoadAccessoires')) {
1237  return;
1238  }
1239 
1240  $oAcclist = oxNew("oxarticlelist");
1241  $oAcclist->setSqlLimit(0, $myConfig->getConfigParam('iNrofCrossellArticles'));
1242  $oAcclist->loadArticleAccessoires($this->oxarticles__oxid->value);
1243 
1244  if ($oAcclist->count()) {
1245  return $oAcclist;
1246  }
1247  }
1248 
1254  public function getSimilarProducts()
1255  {
1256  // Performance
1257  $myConfig = $this->getConfig();
1258  if (!$myConfig->getConfigParam('bl_perfLoadSimilar')) {
1259  return;
1260  }
1261 
1262  // Check configured number of similar products (bug #6062)
1263  if($myConfig->getConfigParam('iNrofSimilarArticles') < 1) {
1264  return;
1265  }
1266 
1267  $sArticleTable = $this->getViewName();
1268 
1269  $sAttribs = '';
1270  $iCnt = 0;
1271  $this->_getAttribsString($sAttribs, $iCnt);
1272 
1273  if (!$sAttribs) {
1274  return null;
1275  }
1276 
1277  $aList = $this->_getSimList($sAttribs, $iCnt);
1278 
1279  if (count($aList)) {
1280  uasort($aList, 'cmpart');
1281 
1282  $sSearch = $this->_generateSimListSearchStr($sArticleTable, $aList);
1283 
1284  $oSimilarlist = oxNew('oxarticlelist');
1285  $oSimilarlist->setSqlLimit(0, $myConfig->getConfigParam('iNrofSimilarArticles'));
1286  $oSimilarlist->selectString($sSearch);
1287 
1288  return $oSimilarlist;
1289  }
1290  }
1291 
1298  {
1299  // Performance
1300  $myConfig = $this->getConfig();
1301  if (!$myConfig->getConfigParam('bl_perfLoadCustomerWhoBoughtThis')) {
1302  return;
1303  }
1304 
1305  // selecting products that fits
1306  $sQ = $this->_generateSearchStrForCustomerBought();
1307 
1308  $oArticles = oxNew('oxarticlelist');
1309  $oArticles->setSqlLimit(0, $myConfig->getConfigParam('iNrofCustomerWhoArticles'));
1310  $oArticles->selectString($sQ);
1311  if ($oArticles->count()) {
1312  return $oArticles;
1313  }
1314  }
1315 
1322  public function loadAmountPriceInfo()
1323  {
1324  $myConfig = $this->getConfig();
1325  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice || !$this->_blCalcPrice || !$this->hasAmountPrice()) {
1326  return array();
1327  }
1328 
1329  if ($this->_oAmountPriceInfo === null) {
1330  $this->_oAmountPriceInfo = array();
1331  if (count(($aAmPriceList = $this->_getAmountPriceList()->getArray()))) {
1332  $this->_oAmountPriceInfo = $this->_fillAmountPriceList($aAmPriceList);
1333  }
1334  }
1335 
1336  return $this->_oAmountPriceInfo;
1337  }
1338 
1346  public function getSelectLists($sKeyPrefix = null)
1347  {
1348  //#1468C - more then one article in basket with different selectlist...
1349  //optionall function parameter $sKeyPrefix added, used only in basket.php
1350  $sKey = $this->getId();
1351  if (isset($sKeyPrefix)) {
1352  $sKey = $sKeyPrefix . '__' . $sKey;
1353  }
1354 
1355  if (!isset(self::$_aSelList[$sKey])) {
1356  $oDb = oxDb::getDb();
1357  $sSLViewName = getViewName('oxselectlist');
1358 
1359  $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
1360  where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
1361 
1362  // all selectlists this article has
1363  $oLists = oxNew('oxlist');
1364  $oLists->init('oxselectlist');
1365  $oLists->selectString(sprintf($sQ, $oDb->quote($this->getId())));
1366 
1367  //#1104S if this is variant ant it has no selectlists, trying with parent
1368  if ($oLists->count() == 0 && $this->oxarticles__oxparentid->value) {
1369  $oLists->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
1370  }
1371 
1372  // We do not need to calculate price here as there are method to get current article vat
1373  /*if ( $this->getPrice() != null ) {
1374  $dVat = $this->getPrice()->getVat();
1375  }*/
1376  $dVat = $this->getArticleVat();
1377 
1378  $iCnt = 0;
1379  self::$_aSelList[$sKey] = array();
1380  foreach ($oLists as $oSelectlist) {
1381  self::$_aSelList[$sKey][$iCnt] = $oSelectlist->getFieldList($dVat);
1382  self::$_aSelList[$sKey][$iCnt]['name'] = $oSelectlist->oxselectlist__oxtitle->value;
1383  $iCnt++;
1384  }
1385  }
1386 
1387  return self::$_aSelList[$sKey];
1388  }
1389 
1395  public function getVariantsCount()
1396  {
1397  return $this->oxarticles__oxvarcount->value;
1398  }
1399 
1405  public function hasMdVariants()
1406  {
1407  return $this->_blHasMdVariants;
1408  }
1409 
1415  public function hasIntangibleAgreement()
1416  {
1417  return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxnonmaterial->value && !$this->hasDownloadableAgreement();
1418  }
1419 
1425  public function hasDownloadableAgreement()
1426  {
1427  return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxisdownloadable->value;
1428  }
1429 
1439  public function getVariantSelections($aFilterIds = null, $sActVariantId = null, $iLimit = 0)
1440  {
1441  $iLimit = (int) $iLimit;
1442  if (!isset($this->_aVariantSelections[$iLimit])) {
1443  $aVariantSelections = false;
1444  if ($this->oxarticles__oxvarcount->value) {
1445  $oVariants = $this->getVariants(false);
1446  $aVariantSelections = oxNew("oxVariantHandler")->buildVariantSelections($this->oxarticles__oxvarname->getRawValue(), $oVariants, $aFilterIds, $sActVariantId, $iLimit);
1447 
1448  if (!empty($oVariants) && empty($aVariantSelections['rawselections'])) {
1449  $aVariantSelections = false;
1450  }
1451  }
1452  $this->_aVariantSelections[$iLimit] = $aVariantSelections;
1453  }
1454 
1455  return $this->_aVariantSelections[$iLimit];
1456  }
1457 
1466  public function getSelections($iLimit = null, $aFilter = null)
1467  {
1468  $sId = $this->getId() . ((int) $iLimit);
1469  if (!array_key_exists($sId, self::$_aSelections)) {
1470 
1471  $oDb = oxDb::getDb();
1472  $sSLViewName = getViewName('oxselectlist');
1473 
1474  $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
1475  where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
1476 
1477  if (($iLimit = (int) $iLimit)) {
1478  $sQ .= " limit $iLimit ";
1479  }
1480 
1481  // vat value for price
1482  $dVat = 0;
1483  if (($oPrice = $this->getPrice()) != null) {
1484  $dVat = $oPrice->getVat();
1485  }
1486 
1487  // all selectlists this article has
1488  $oList = oxNew('oxlist');
1489  $oList->init('oxselectlist');
1490  $oList->getBaseObject()->setVat($dVat);
1491  $oList->selectString(sprintf($sQ, $oDb->quote($this->getId())));
1492 
1493  //#1104S if this is variant and it has no selectlists, trying with parent
1494  if ($oList->count() == 0 && $this->oxarticles__oxparentid->value) {
1495  $oList->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
1496  }
1497 
1498  self::$_aSelections[$sId] = $oList->count() ? $oList : false;
1499  }
1500 
1501  if (self::$_aSelections[$sId]) {
1502  // marking active from filter
1503  $aFilter = ($aFilter === null) ? oxRegistry::getConfig()->getRequestParameter("sel") : $aFilter;
1504  if ($aFilter) {
1505  $iSelIdx = 0;
1506  foreach (self::$_aSelections[$sId] as $oSelection) {
1507  if (isset($aFilter[$iSelIdx])) {
1508  $oSelection->setActiveSelectionByIndex($aFilter[$iSelIdx]);
1509  }
1510  $iSelIdx++;
1511  }
1512  }
1513  }
1514 
1515  return self::$_aSelections[$sId];
1516  }
1517 
1526  public function getFullVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
1527  {
1528  return $this->_loadVariantList(false, $blRemoveNotOrderables, $blForceCoreTable);
1529  }
1530 
1540  public function getVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
1541  {
1542  return $this->_loadVariantList($this->_isInList(), $blRemoveNotOrderables, $blForceCoreTable);
1543  }
1544 
1550  public function getSimpleVariants()
1551  {
1552  if ($this->oxarticles__oxvarcount->value) {
1553  return $this->getVariants();
1554  }
1555  }
1556 
1565  public function getAdminVariants($sLanguage = null)
1566  {
1567  $oVariants = oxNew('oxarticlelist');
1568  if (($sId = $this->getId())) {
1569 
1570  $oBaseObj = $oVariants->getBaseObject();
1571 
1572  if (is_null($sLanguage)) {
1573  $oBaseObj->setLanguage(oxRegistry::getLang()->getBaseLanguage());
1574  } else {
1575  $oBaseObj->setLanguage($sLanguage);
1576  }
1577 
1578  $sSql = "select * from " . $oBaseObj->getViewName() . " where oxparentid = '{$sId}' order by oxsort ";
1579  $oVariants->selectString($sSql);
1580 
1581  //if we have variants then depending on config option the parent may be non buyable
1582  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && ($oVariants->count() > 0)) {
1583  //$this->blNotBuyable = true;
1584  $this->_blNotBuyableParent = true;
1585  }
1586  }
1587 
1588  return $oVariants;
1589  }
1590 
1598  public function getCategory()
1599  {
1600  $oCategory = oxNew('oxcategory');
1601  $oCategory->setLanguage($this->getLanguage());
1602 
1603  // variant handling
1604  $sOXID = $this->getId();
1605  if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
1606  $sOXID = $this->oxarticles__oxparentid->value;
1607  }
1608 
1609  if ($sOXID) {
1610  // if the oxcategory instance of this article is not cached
1611  if (!isset($this->_aCategoryCache[$sOXID])) {
1612  startPRofile('getCategory');
1613  $oStr = getStr();
1614  $sWhere = $oCategory->getSqlActiveSnippet();
1615  $sSelect = $this->_generateSearchStr($sOXID);
1616  $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " order by oxobject2category.oxtime limit 1";
1617 
1618  // category not found ?
1619  if (!$oCategory->assignRecord($sSelect)) {
1620 
1621  $sSelect = $this->_generateSearchStr($sOXID, true);
1622  $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " limit 1";
1623 
1624  // looking for price category
1625  if (!$oCategory->assignRecord($sSelect)) {
1626  $oCategory = null;
1627  }
1628  }
1629  // add the category instance to cache
1630  $this->_aCategoryCache[$sOXID] = $oCategory;
1631  stopPRofile('getCategory');
1632  } else {
1633  // if the oxcategory instance is cached
1634  $oCategory = $this->_aCategoryCache[$sOXID];
1635  }
1636  }
1637 
1638  return $oCategory;
1639  }
1640 
1649  public function getCategoryIds($blActCats = false, $blSkipCache = false)
1650  {
1651  $sArticleId = $this->getId();
1652 
1653  if (!isset(self::$_aArticleCats[$sArticleId]) || $blSkipCache) {
1654 
1655  $sSql = $this->_getCategoryIdsSelect($blActCats);
1656  $aCategoryIds = $this->_selectCategoryIds($sSql, 'oxcatnid');
1657 
1658  $sSql = $this->getSqlForPriceCategories();
1659  $aPriceCategoryIds = $this->_selectCategoryIds($sSql, 'oxid');
1660 
1661  self::$_aArticleCats[$sArticleId] = array_unique(array_merge($aCategoryIds, $aPriceCategoryIds));
1662  }
1663 
1664  return self::$_aArticleCats[$sArticleId];
1665  }
1666 
1676  public function getVendor($blShopCheck = true)
1677  {
1678  if (($sVendorId = $this->getVendorId())) {
1679  $oVendor = oxNew('oxvendor');
1680  } elseif (!$blShopCheck && $this->oxarticles__oxvendorid->value) {
1681  $oVendor = oxNew('oxi18n');
1682  $oVendor->init('oxvendor');
1683  $oVendor->setReadOnly(true);
1684  $sVendorId = $this->oxarticles__oxvendorid->value;
1685  }
1686  if ($sVendorId && $oVendor->load($sVendorId) && $oVendor->oxvendor__oxactive->value) {
1687 
1688  return $oVendor;
1689  }
1690 
1691  return null;
1692  }
1693 
1701  public function getVendorId($blForceReload = false)
1702  {
1703  $sVendorId = false;
1704  if ($this->oxarticles__oxvendorid->value) {
1705  $sVendorId = $this->oxarticles__oxvendorid->value;
1706 
1707  }
1708 
1709  return $sVendorId;
1710  }
1711 
1719  public function getManufacturerId($blForceReload = false)
1720  {
1721  $sManufacturerId = false;
1722  if ($this->oxarticles__oxmanufacturerid->value) {
1723 
1724  $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
1725 
1726  }
1727 
1728  return $sManufacturerId;
1729  }
1730 
1740  public function getManufacturer($blShopCheck = true)
1741  {
1742  $oManufacturer = oxNew('oxmanufacturer');
1743  if (!($sManufacturerId = $this->getManufacturerId()) &&
1744  !$blShopCheck && $this->oxarticles__oxmanufacturerid->value
1745  ) {
1746  $oManufacturer->setReadOnly(true);
1747  $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
1748  }
1749 
1750  if ($sManufacturerId && $oManufacturer->load($sManufacturerId)) {
1751  if (!$this->getConfig()->getConfigParam('bl_perfLoadManufacturerTree')) {
1752  $oManufacturer->setReadOnly(true);
1753  }
1754  $oManufacturer = $oManufacturer->oxmanufacturers__oxactive->value ? $oManufacturer : null;
1755  } else {
1756  $oManufacturer = null;
1757  }
1758 
1759  return $oManufacturer;
1760  }
1761 
1769  public function inCategory($sCatNid)
1770  {
1771  return in_array($sCatNid, $this->getCategoryIds());
1772  }
1773 
1782  public function isAssignedToCategory($sCatId)
1783  {
1784  // variant handling
1785  $sOXID = $this->getId();
1786  if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
1787  $sOXID = $this->oxarticles__oxparentid->value;
1788  }
1789 
1790  $oDb = oxDb::getDb();
1791  $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId);
1792  $sOXID = $oDb->getOne($sSelect);
1793  // article is assigned to passed category!
1794  if (isset($sOXID) && $sOXID) {
1795  return true;
1796  }
1797 
1798  // maybe this category is price category ?
1799  if ($this->getConfig()->getConfigParam('bl_perfLoadPrice') && $this->_blLoadPrice) {
1800  $dPriceFromTo = $this->getPrice()->getBruttoPrice();
1801  if ($dPriceFromTo > 0) {
1802  $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo);
1803  $sOXID = $oDb->getOne($sSelect);
1804  // article is assigned to passed category!
1805  if (isset($sOXID) && $sOXID) {
1806  return true;
1807  }
1808  }
1809  }
1810 
1811  return false;
1812  }
1813 
1819  public function getTPrice()
1820  {
1821  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1822  return;
1823  }
1824 
1825  // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
1826  if ($this->_oTPrice !== null) {
1827  return $this->_oTPrice;
1828  }
1829 
1830  $oPrice = $this->_getPriceObject();
1831 
1832  $dBasePrice = $this->oxarticles__oxtprice->value;
1833  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
1834 
1835  $oPrice->setPrice($dBasePrice);
1836 
1837  $this->_applyVat($oPrice, $this->getArticleVat());
1838  $this->_applyCurrency($oPrice);
1839 
1840  if ($this->isParentNotBuyable()) {
1841  // if parent article is not buyable then compare agains min article variant price
1842  $oPrice2 = $this->getVarMinPrice();
1843  } else {
1844  // else compare against article price
1845  $oPrice2 = $this->getPrice();
1846  }
1847 
1848  if ($oPrice->getPrice() <= $oPrice2->getPrice()) {
1849  // if RRP price is less or equal to comparable price then return
1850  return;
1851  }
1852 
1853  $this->_oTPrice = $oPrice;
1854 
1855  return $this->_oTPrice;
1856  }
1857 
1863  public function skipDiscounts()
1864  {
1865  // already loaded skip discounts config
1866  if ($this->_blSkipDiscounts !== null) {
1867  return $this->_blSkipDiscounts;
1868  }
1869 
1870  if ($this->oxarticles__oxskipdiscounts->value) {
1871  return true;
1872  }
1873 
1874 
1875  $this->_blSkipDiscounts = false;
1876  if (oxRegistry::get("oxDiscountList")->hasSkipDiscountCategories()) {
1877 
1878  $oDb = oxDb::getDb();
1879  $sO2CView = getViewName('oxobject2category', $this->getLanguage());
1880  $sViewName = getViewName('oxcategories', $this->getLanguage());
1881  $sSelect = "select 1 from $sO2CView as $sO2CView left join {$sViewName} on {$sViewName}.oxid = $sO2CView.oxcatnid
1882  where $sO2CView.oxobjectid=" . $oDb->quote($this->getId()) . " and {$sViewName}.oxactive = 1 and {$sViewName}.oxskipdiscounts = '1' ";
1883  $this->_blSkipDiscounts = ($oDb->getOne($sSelect) == 1);
1884  }
1885 
1886  return $this->_blSkipDiscounts;
1887  }
1888 
1894  public function setPrice(oxPrice $oPrice)
1895  {
1896  $this->_oPrice = $oPrice;
1897  }
1898 
1907  public function getBasePrice($dAmount = 1)
1908  {
1909  // override this function if you want e.g. different prices
1910  // for diff. user groups.
1911 
1912  // Performance
1913  $myConfig = $this->getConfig();
1914  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1915  return;
1916  }
1917 
1918  // GroupPrice or DB price ajusted by AmountPrice
1919  $dPrice = $this->_getAmountPrice($dAmount);
1920 
1921 
1922  return $dPrice;
1923  }
1924 
1932  public function getPrice($dAmount = 1)
1933  {
1934  $myConfig = $this->getConfig();
1935  // Performance
1936  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1937  return;
1938  }
1939 
1940  // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
1941  if ($dAmount != 1 || $this->_oPrice === null) {
1942 
1943  // module
1944  $dBasePrice = $this->getBasePrice($dAmount);
1945  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
1946 
1947  $oPrice = $this->_getPriceObject();
1948 
1949  $oPrice->setPrice($dBasePrice);
1950 
1951  // price handling
1952  if (!$this->_blCalcPrice && $dAmount == 1) {
1953  return $this->_oPrice = $oPrice;
1954  }
1955 
1956  $this->_calculatePrice($oPrice);
1957  if ($dAmount != 1) {
1958  return $oPrice;
1959  }
1960 
1961  $this->_oPrice = $oPrice;
1962  }
1963 
1964  return $this->_oPrice;
1965  }
1966 
1972  public function setArticleUser($oUser)
1973  {
1974  $this->_oUser = $oUser;
1975  }
1976 
1982  public function getArticleUser()
1983  {
1984  if ($this->_oUser) {
1985  return $this->_oUser;
1986  }
1987 
1988  return $this->getUser();
1989  }
1990 
2000  public function getBasketPrice($dAmount, $aSelList, $oBasket)
2001  {
2002  $oUser = $oBasket->getBasketUser();
2003  $this->setArticleUser($oUser);
2004 
2005  $oBasketPrice = $this->_getPriceObject($oBasket->isCalculationModeNetto());
2006 
2007  // get base price
2008  $dBasePrice = $this->getBasePrice($dAmount);
2009 
2010  $dBasePrice = $this->_modifySelectListPrice($dBasePrice, $aSelList);
2011  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat(), $oBasket->isCalculationModeNetto());
2012 
2013  // applying select list price
2014 
2015  // setting price
2016  $oBasketPrice->setPrice($dBasePrice);
2017 
2018  $dVat = oxRegistry::get("oxVatSelector")->getBasketItemVat($this, $oBasket);
2019  $this->_calculatePrice($oBasketPrice, $dVat);
2020 
2021  // returning final price object
2022  return $oBasketPrice;
2023  }
2024 
2033  public function delete($sOXID = null)
2034  {
2035  if (!$sOXID) {
2036  $sOXID = $this->getId();
2037  }
2038  if (!$sOXID) {
2039  return false;
2040  }
2041 
2042 
2043 
2044  // #2339 delete first variants before deleting parent product
2045  $this->_deleteVariantRecords($sOXID);
2046  $this->load($sOXID);
2047  $this->_deletePics();
2048  $this->_onChangeResetCounts($sOXID, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
2049 
2050  // delete self
2051  parent::delete($sOXID);
2052 
2053  $rs = $this->_deleteRecords($sOXID);
2054 
2055  oxRegistry::get("oxSeoEncoderArticle")->onDeleteArticle($this);
2056 
2057  $this->onChange(ACTION_DELETE, $sOXID, $this->oxarticles__oxparentid->value);
2058 
2059  return $rs->EOF;
2060  }
2061 
2070  public function reduceStock($dAmount, $blAllowNegativeStock = false)
2071  {
2072  $this->beforeUpdate();
2073 
2074  $iStockCount = $this->oxarticles__oxstock->value - $dAmount;
2075  if (!$blAllowNegativeStock && ($iStockCount < 0)) {
2076  $dAmount += $iStockCount;
2077  $iStockCount = 0;
2078  }
2079  $this->oxarticles__oxstock = new oxField($iStockCount);
2080 
2081  $oDb = oxDb::getDb();
2082  $oDb->execute('update oxarticles set oxarticles.oxstock = ' . $oDb->quote($iStockCount) . ' where oxarticles.oxid = ' . $oDb->quote($this->getId()));
2083  $this->onChange(ACTION_UPDATE_STOCK);
2084 
2085  return $dAmount;
2086  }
2087 
2096  public function updateSoldAmount($dAmount = 0)
2097  {
2098  if (!$dAmount) {
2099  return;
2100  }
2101 
2102  // article is not variant - should be updated current amount
2103  if (!$this->oxarticles__oxparentid->value) {
2104  //updating by SQL query, due to wrong behaviour if saving article using not admin mode
2105  $dAmount = (double) $dAmount;
2106  $oDb = oxDb::getDb();
2107  $rs = $oDb->execute("update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $dAmount where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
2108  } elseif ($this->oxarticles__oxparentid->value) {
2109  // article is variant - should be updated this article parent amount
2110  $oUpdateArticle = $this->getParentArticle();
2111  if ($oUpdateArticle) {
2112  $oUpdateArticle->updateSoldAmount($dAmount);
2113  }
2114  }
2115 
2116  return $rs;
2117  }
2118 
2124  public function disableReminder()
2125  {
2126  $oDb = oxDb::getDb();
2127 
2128  return $oDb->execute("update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
2129  }
2130 
2136  public function save()
2137  {
2138  $this->_assignParentDependFields();
2139 
2140  if (($blRet = parent::save())) {
2141  // saving long description
2142  $this->_saveArtLongDesc();
2143  }
2144 
2145  return $blRet;
2146  }
2147 
2151  public function resetParent()
2152  {
2153  $sParentId = $this->oxarticles__oxparentid->value;
2154  $this->oxarticles__oxparentid = new oxField('', oxField::T_RAW);
2155  $this->_blAllowEmptyParentId = true;
2156  $this->save();
2157  $this->_blAllowEmptyParentId = false;
2158 
2159  if ($sParentId !== '') {
2160  $this->onChange(ACTION_UPDATE, null, $sParentId);
2161  }
2162  }
2163 
2164 
2171  public function getPictureGallery()
2172  {
2173  $myConfig = $this->getConfig();
2174 
2175  //initialize
2176  $blMorePic = false;
2177  $aArtPics = array();
2178  $aArtIcons = array();
2179  $iActPicId = 1;
2180  $sActPic = $this->getPictureUrl($iActPicId);
2181 
2182  if (oxRegistry::getConfig()->getRequestParameter('actpicid')) {
2183  $iActPicId = oxRegistry::getConfig()->getRequestParameter('actpicid');
2184  }
2185 
2186  $oStr = getStr();
2187  $iCntr = 0;
2188  $iPicCount = $myConfig->getConfigParam('iPicCount');
2189  $blCheckActivePicId = true;
2190 
2191  for ($i = 1; $i <= $iPicCount; $i++) {
2192  $sPicVal = $this->getPictureUrl($i);
2193  $sIcoVal = $this->getIconUrl($i);
2194  if (!$oStr->strstr($sIcoVal, 'nopic_ico.jpg') && !$oStr->strstr($sIcoVal, 'nopic.jpg') &&
2195  !$oStr->strstr($sPicVal, 'nopic_ico.jpg') && !$oStr->strstr($sPicVal, 'nopic.jpg') &&
2196  $sPicVal !== null
2197  ) {
2198  if ($iCntr) {
2199  $blMorePic = true;
2200  }
2201  $aArtIcons[$i] = $sIcoVal;
2202  $aArtPics[$i] = $sPicVal;
2203  $iCntr++;
2204 
2205  if ($iActPicId == $i) {
2206  $sActPic = $sPicVal;
2207  $blCheckActivePicId = false;
2208  }
2209 
2210  } elseif ($blCheckActivePicId && $iActPicId <= $i) {
2211  // if picture is empty, setting active pic id to next
2212  // picture
2213  $iActPicId++;
2214  }
2215  }
2216 
2217  $blZoomPic = false;
2218  $aZoomPics = array();
2219  $iZoomPicCount = $myConfig->getConfigParam('iPicCount');
2220 
2221  for ($j = 1, $c = 1; $j <= $iZoomPicCount; $j++) {
2222  $sVal = $this->getZoomPictureUrl($j);
2223 
2224  if ($sVal && !$oStr->strstr($sVal, 'nopic.jpg')) {
2225  $blZoomPic = true;
2226  $aZoomPics[$c]['id'] = $c;
2227  $aZoomPics[$c]['file'] = $sVal;
2228  //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
2229  if (!$sVal) {
2230  $aZoomPics[$c]['file'] = "nopic.jpg";
2231  }
2232  $c++;
2233  }
2234  }
2235 
2236  $aPicGallery = array('ActPicID' => $iActPicId,
2237  'ActPic' => $sActPic,
2238  'MorePics' => $blMorePic,
2239  'Pics' => $aArtPics,
2240  'Icons' => $aArtIcons,
2241  'ZoomPic' => $blZoomPic,
2242  'ZoomPics' => $aZoomPics);
2243 
2244  return $aPicGallery;
2245  }
2246 
2260  public function onChange($sAction = null, $sOXID = null, $sParentID = null)
2261  {
2262  $myConfig = $this->getConfig();
2263 
2264  if (!isset($sOXID)) {
2265  if ($this->getId()) {
2266  $sOXID = $this->getId();
2267  }
2268  if (!isset ($sOXID)) {
2269  $sOXID = $this->oxarticles__oxid->value;
2270  }
2271  if ($this->oxarticles__oxparentid->value) {
2272  $sParentID = $this->oxarticles__oxparentid->value;
2273  }
2274  }
2275  if (!isset($sOXID)) {
2276  return;
2277  }
2278 
2279  //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
2280  if ($myConfig->getConfigParam('blUseStock')) {
2281  //if article has variants then updating oxvarstock field
2282  //getting parent id
2283  if (!isset($sParentID)) {
2284  $oDb = oxDb::getDb();
2285  $sQ = 'select oxparentid from oxarticles where oxid = ' . $oDb->quote($sOXID);
2286  $sParentID = $oDb->getOne($sQ);
2287  }
2288  //if we have parent id then update stock
2289  if ($sParentID) {
2290  $this->_onChangeUpdateStock($sParentID);
2291  }
2292  }
2293  //if we have parent id then update count
2294  //update count even if blUseStock is not active
2295  if ($sParentID) {
2296  $this->_onChangeUpdateVarCount($sParentID);
2297  }
2298 
2299  $sId = ($sParentID) ? $sParentID : $sOXID;
2300  $this->_setVarMinMaxPrice($sId);
2301 
2302  $this->_updateParentDependFields();
2303 
2304  // resetting articles count cache if stock has changed and some
2305  // articles goes offline (M:1448)
2306  if ($sAction === ACTION_UPDATE_STOCK) {
2307  $this->_assignStock();
2308  $this->_onChangeStockResetCount($sOXID);
2309  }
2310 
2311  }
2312 
2319  public function getCustomVAT()
2320  {
2321  if (isset($this->oxarticles__oxvat->value)) {
2322  return $this->oxarticles__oxvat->value;
2323  }
2324  }
2325 
2334  public function checkForStock($dAmount, $dArtStockAmount = 0)
2335  {
2336  $myConfig = $this->getConfig();
2337  if (!$myConfig->getConfigParam('blUseStock')) {
2338  return true;
2339  }
2340 
2342  // fetching DB info as its up-to-date
2343  $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = ' . $oDb->quote($this->getId());
2344  $rs = $oDb->select($sQ);
2345 
2346  $iOnStock = 0;
2347  $iStockFlag = 0;
2348  if ($rs !== false && $rs->recordCount() > 0) {
2349  $iOnStock = $rs->fields['oxstock'] - $dArtStockAmount;
2350  $iStockFlag = $rs->fields['oxstockflag'];
2351 
2352  // foreign stock is also always considered as on stock
2353  if ($iStockFlag == 1 || $iStockFlag == 4) {
2354  return true;
2355  }
2356  if (!$myConfig->getConfigParam('blAllowUnevenAmounts')) {
2357  $iOnStock = floor($iOnStock);
2358  }
2359  }
2360  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
2361  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
2362  }
2363  if ($iOnStock >= $dAmount) {
2364  return true;
2365  } else {
2366  if ($iOnStock > 0) {
2367  return $iOnStock;
2368  } else {
2369  $oEx = oxNew('oxArticleInputException');
2370  $oEx->setMessage('ERROR_MESSAGE_ARTICLE_ARTICLE_NOT_BUYABLE');
2371  oxRegistry::get("oxUtilsView")->addErrorToDisplay($oEx);
2372 
2373  return false;
2374  }
2375  }
2376  }
2377 
2378 
2384  public function getLongDescription()
2385  {
2386  if ($this->_oLongDesc === null) {
2387  // initializing
2388  $this->_oLongDesc = new oxField();
2389 
2390 
2391  // choosing which to get..
2392  $sOxid = $this->getId();
2393  $sViewName = getViewName('oxartextends', $this->getLanguage());
2394 
2395  $oDb = oxDb::getDb();
2396  $sDbValue = $oDb->getOne("select oxlongdesc from {$sViewName} where oxid = " . $oDb->quote($sOxid));
2397 
2398  if ($sDbValue != false) {
2399  $this->_oLongDesc->setValue($sDbValue, oxField::T_RAW);
2400  } elseif ($this->oxarticles__oxparentid->value) {
2401  if (!$this->isAdmin() || $this->_blLoadParentData) {
2402  $oParent = $this->getParentArticle();
2403  if ($oParent) {
2404  $this->_oLongDesc->setValue($oParent->getLongDescription()->getRawValue(), oxField::T_RAW);
2405  }
2406  }
2407  }
2408  }
2409 
2410  return $this->_oLongDesc;
2411  }
2412 
2419  public function getLongDesc()
2420  {
2421  return oxRegistry::get("oxUtilsView")->parseThroughSmarty($this->getLongDescription()->getRawValue(), $this->getId() . $this->getLanguage(), null, true);
2422  }
2423 
2431  public function setArticleLongDesc($sDesc)
2432  {
2433 
2434  // setting current value
2435  $this->_oLongDesc = new oxField($sDesc, oxField::T_RAW);
2436  $this->oxarticles__oxlongdesc = new oxField($sDesc, oxField::T_RAW);
2437  }
2438 
2444  public function getAttributes()
2445  {
2446  if ($this->_oAttributeList === null) {
2447  $this->_oAttributeList = oxNew('oxattributelist');
2448  $this->_oAttributeList->loadAttributes($this->getId(), $this->getParentId());
2449  }
2450 
2451  return $this->_oAttributeList;
2452  }
2453 
2460  {
2461  if ($this->_oAttributeList === null) {
2462  $this->_oAttributeList = oxNew('oxattributelist');
2463  $this->_oAttributeList->loadAttributesDisplayableInBasket($this->getId(), $this->getParentId());
2464  }
2465 
2466  return $this->_oAttributeList;
2467  }
2468 
2469 
2476  public function appendLink($sAddParams, $iLang = null)
2477  {
2478  if ($sAddParams) {
2479  if ($iLang === null) {
2480  $iLang = $this->getLanguage();
2481  }
2482 
2483  $this->_aSeoAddParams[$iLang] = isset($this->_aSeoAddParams[$iLang]) ? $this->_aSeoAddParams[$iLang] . "&amp;" : "";
2484  $this->_aSeoAddParams[$iLang] .= $sAddParams;
2485  }
2486  }
2487 
2496  public function getBaseSeoLink($iLang, $blMain = false)
2497  {
2499  $oEncoder = oxRegistry::get("oxSeoEncoderArticle");
2500  if (!$blMain) {
2501  return $oEncoder->getArticleUrl($this, $iLang, $this->getLinkType());
2502  }
2503 
2504  return $oEncoder->getArticleMainUrl($this, $iLang);
2505  }
2506 
2515  public function getLink($iLang = null, $blMain = false)
2516  {
2517  if (!oxRegistry::getUtils()->seoIsActive()) {
2518  return $this->getStdLink($iLang);
2519  }
2520 
2521  if ($iLang === null) {
2522  $iLang = $this->getLanguage();
2523  }
2524 
2525  $iLinkType = $this->getLinkType();
2526  if (!isset($this->_aSeoUrls[$iLang][$iLinkType])) {
2527  $this->_aSeoUrls[$iLang][$iLinkType] = $this->getBaseSeoLink($iLang, $blMain);
2528  }
2529 
2530  $sUrl = $this->_aSeoUrls[$iLang][$iLinkType];
2531  if (isset($this->_aSeoAddParams[$iLang])) {
2532  $sUrl .= ((strpos($sUrl . $this->_aSeoAddParams[$iLang], '?') === false) ? '?' : '&amp;') . $this->_aSeoAddParams[$iLang];
2533  }
2534 
2535  return $sUrl;
2536  }
2537 
2546  public function getMainLink($iLang = null)
2547  {
2548  return $this->getLink($iLang, true);
2549  }
2550 
2556  public function setLinkType($iType)
2557  {
2558  // resetting details link, to force new
2559  $this->_sDetailLink = null;
2560 
2561  // setting link type
2562  $this->_iLinkType = (int) $iType;
2563  }
2564 
2570  public function getLinkType()
2571  {
2572  return $this->_iLinkType;
2573  }
2574 
2581  public function appendStdLink($sAddParams, $iLang = null)
2582  {
2583  if ($sAddParams) {
2584  if ($iLang === null) {
2585  $iLang = $this->getLanguage();
2586  }
2587 
2588  $this->_aStdAddParams[$iLang] = isset($this->_aStdAddParams[$iLang]) ? $this->_aStdAddParams[$iLang] . "&amp;" : "";
2589  $this->_aStdAddParams[$iLang] .= $sAddParams;
2590  }
2591  }
2592 
2602  public function getBaseStdLink($iLang, $blAddId = true, $blFull = true)
2603  {
2604  $sUrl = '';
2605  if ($blFull) {
2606  //always returns shop url, not admin
2607  $sUrl = $this->getConfig()->getShopUrl($iLang, false);
2608  }
2609 
2610  $sUrl .= "index.php?cl=details" . ($blAddId ? "&amp;anid=" . $this->getId() : "");
2611 
2612  return $sUrl . (isset($this->_aStdAddParams[$iLang]) ? "&amp;" . $this->_aStdAddParams[$iLang] : "");
2613  }
2614 
2623  public function getStdLink($iLang = null, $aParams = array())
2624  {
2625  if ($iLang === null) {
2626  $iLang = $this->getLanguage();
2627  }
2628 
2629  if (!isset($this->_aStdUrls[$iLang])) {
2630  $this->_aStdUrls[$iLang] = $this->getBaseStdLink($iLang);
2631  }
2632 
2633  return oxRegistry::get("oxUtilsUrl")->processUrl($this->_aStdUrls[$iLang], true, $aParams, $iLang);
2634  }
2635 
2641  public function getMediaUrls()
2642  {
2643  if ($this->_aMediaUrls === null) {
2644  $this->_aMediaUrls = oxNew("oxlist");
2645  $this->_aMediaUrls->init("oxmediaurl");
2646  $this->_aMediaUrls->getBaseObject()->setLanguage($this->getLanguage());
2647 
2648  $sViewName = getViewName("oxmediaurls", $this->getLanguage());
2649  $sQ = "select * from {$sViewName} where oxobjectid = '" . $this->getId() . "'";
2650  $this->_aMediaUrls->selectString($sQ);
2651  }
2652 
2653  return $this->_aMediaUrls;
2654  }
2655 
2661  public function getDynImageDir()
2662  {
2663  return $this->_sDynImageDir;
2664  }
2665 
2671  public function getDispSelList()
2672  {
2673  if ($this->_aDispSelList === null) {
2674  if ($this->getConfig()->getConfigParam('bl_perfLoadSelectLists') && $this->getConfig()->getConfigParam('bl_perfLoadSelectListsInAList')) {
2675  $this->_aDispSelList = $this->getSelectLists();
2676  }
2677  }
2678 
2679  return $this->_aDispSelList;
2680  }
2681 
2687  public function getMoreDetailLink()
2688  {
2689  if ($this->_sMoreDetailLink == null) {
2690 
2691  // and assign special article values
2692  $this->_sMoreDetailLink = $this->getConfig()->getShopHomeURL() . 'cl=moredetails';
2693 
2694  // not always it is okey, as not all the time active category is the same as primary article cat.
2695  if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
2696  $this->_sMoreDetailLink .= '&amp;cnid=' . $sActCat;
2697  }
2698  $this->_sMoreDetailLink .= '&amp;anid=' . $this->getId();
2699  $this->_sMoreDetailLink = $this->_sMoreDetailLink;
2700  }
2701 
2702  return $this->_sMoreDetailLink;
2703  }
2704 
2710  public function getToBasketLink()
2711  {
2712  if ($this->_sToBasketLink == null) {
2713  $myConfig = $this->getConfig();
2714 
2715  if (oxRegistry::getUtils()->isSearchEngine()) {
2716  $this->_sToBasketLink = $this->getLink();
2717  } else {
2718  // and assign special article values
2719  $this->_sToBasketLink = $myConfig->getShopHomeURL();
2720 
2721  // override some classes as these should never showup
2722  $sActClass = oxRegistry::getConfig()->getRequestParameter('cl');
2723  if ($sActClass == 'thankyou') {
2724  $sActClass = 'basket';
2725  }
2726  $this->_sToBasketLink .= 'cl=' . $sActClass;
2727 
2728  // this is not very correct
2729  if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
2730  $this->_sToBasketLink .= '&amp;cnid=' . $sActCat;
2731  }
2732 
2733  $this->_sToBasketLink .= '&amp;fnc=tobasket&amp;aid=' . $this->getId() . '&amp;anid=' . $this->getId();
2734 
2735  if ($sTpl = basename(oxRegistry::getConfig()->getRequestParameter('tpl'))) {
2736  $this->_sToBasketLink .= '&amp;tpl=' . $sTpl;
2737  }
2738  }
2739  }
2740 
2741  return $this->_sToBasketLink;
2742  }
2743 
2749  public function getStockStatus()
2750  {
2751  return $this->_iStockStatus;
2752  }
2753 
2759  public function getDeliveryDate()
2760  {
2761  if ($this->oxarticles__oxdelivery->value != '0000-00-00') {
2762  return oxRegistry::get("oxUtilsDate")->formatDBDate($this->oxarticles__oxdelivery->value);
2763  }
2764 
2765  return false;
2766  }
2767 
2775  public function getFTPrice()
2776  {
2777  // module
2778  if ($oPrice = $this->getTPrice()) {
2779  if ($dPrice = $this->_getPriceForView($oPrice)) {
2780  return oxRegistry::getLang()->formatCurrency($dPrice);
2781  }
2782  }
2783  }
2784 
2792  public function getFPrice()
2793  {
2794  if ($oPrice = $this->getPrice()) {
2795  $dPrice = $this->_getPriceForView($oPrice);
2796 
2797  return oxRegistry::getLang()->formatCurrency($dPrice);
2798  }
2799  }
2800 
2805  public function resetRemindStatus()
2806  {
2807  if ($this->oxarticles__oxremindactive->value == 2 &&
2808  $this->oxarticles__oxremindamount->value <= $this->oxarticles__oxstock->value
2809  ) {
2810  $this->oxarticles__oxremindactive->value = 1;
2811  }
2812  }
2813 
2821  public function getFNetPrice()
2822  {
2823  if ($oPrice = $this->getPrice()) {
2824  return oxRegistry::getLang()->formatCurrency($oPrice->getNettoPrice());
2825  }
2826  }
2827 
2833  public function isParentNotBuyable()
2834  {
2836  }
2837 
2843  public function isNotBuyable()
2844  {
2845  return $this->_blNotBuyable;
2846  }
2847 
2853  public function setBuyableState($blBuyable = false)
2854  {
2855  $this->_blNotBuyable = !$blBuyable;
2856  }
2857 
2863  public function setSelectlist($aSelList)
2864  {
2865  $this->_aDispSelList = $aSelList;
2866  }
2867 
2875  public function getPictureUrl($iIndex = 1)
2876  {
2877  if ($iIndex) {
2878  $sImgName = false;
2879  if (!$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
2880  $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
2881  }
2882 
2883  $sSize = $this->getConfig()->getConfigParam('aDetailImageSizes');
2884 
2885  return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
2886  }
2887  }
2888 
2897  public function getIconUrl($iIndex = 0)
2898  {
2899  $sImgName = false;
2900  $sDirname = "product/1/";
2901  if ($iIndex && !$this->_isFieldEmpty("oxarticles__oxpic{$iIndex}")) {
2902  $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
2903  $sDirname = "product/{$iIndex}/";
2904  } elseif (!$this->_isFieldEmpty("oxarticles__oxicon")) {
2905  $sImgName = basename($this->oxarticles__oxicon->value);
2906  $sDirname = "product/icon/";
2907  } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
2908  $sImgName = basename($this->oxarticles__oxpic1->value);
2909  }
2910 
2911  $sSize = $this->getConfig()->getConfigParam('sIconsize');
2912 
2913  $sIconUrl = oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, $iIndex);
2914 
2915  return $sIconUrl;
2916  }
2917 
2925  public function getThumbnailUrl($bSsl = null)
2926  {
2927  $sImgName = false;
2928  $sDirname = "product/1/";
2929  if (!$this->_isFieldEmpty("oxarticles__oxthumb")) {
2930  $sImgName = basename($this->oxarticles__oxthumb->value);
2931  $sDirname = "product/thumb/";
2932  } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
2933  $sImgName = basename($this->oxarticles__oxpic1->value);
2934  }
2935 
2936  $sSize = $this->getConfig()->getConfigParam('sThumbnailsize');
2937 
2938  return oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, 0, $bSsl);
2939  }
2940 
2948  public function getZoomPictureUrl($iIndex = '')
2949  {
2950  $iIndex = (int) $iIndex;
2951  if ($iIndex > 0 && !$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
2952  $sImgName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
2953  $sSize = $this->getConfig()->getConfigParam("sZoomImageSize");
2954 
2955  return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
2956  }
2957  }
2958 
2964  public function applyVats(oxPrice $oPrice)
2965  {
2966  $this->_applyVAT($oPrice, $this->getArticleVat());
2967  }
2968 
2974  public function applyDiscountsForVariant($oPrice)
2975  {
2976  // apply discounts
2977  if (!$this->skipDiscounts()) {
2978  $oDiscountList = oxRegistry::get("oxDiscountList");
2979  $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
2980 
2981  reset($aDiscounts);
2982  foreach ($aDiscounts as $oDiscount) {
2983  $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
2984  }
2985  $oPrice->calculateDiscount();
2986  }
2987  }
2988 
2994  public function getParentArticle()
2995  {
2996  if (($sParentId = $this->oxarticles__oxparentid->value)) {
2997  $sIndex = $sParentId . "_" . $this->getLanguage();
2998  if (!isset(self::$_aLoadedParents[$sIndex])) {
2999  self::$_aLoadedParents[$sIndex] = oxNew('oxarticle');
3000  self::$_aLoadedParents[$sIndex]->_blLoadPrice = false;
3001  self::$_aLoadedParents[$sIndex]->_blLoadVariants = false;
3002 
3003  if (!self::$_aLoadedParents[$sIndex]->loadInLang($this->getLanguage(), $sParentId)) {
3004  //return false in case parent product failed to load
3005  self::$_aLoadedParents[$sIndex] = false;
3006  }
3007  }
3008 
3009  return self::$_aLoadedParents[$sIndex];
3010  }
3011  }
3012 
3016  public function updateVariantsRemind()
3017  {
3018  // check if it is parent article
3019  if (!$this->isVariant() && $this->_hasAnyVariant()) {
3020  $oDb = oxDb::getDb();
3021  $sOxId = $oDb->quote($this->getId());
3022  $sOxShopId = $oDb->quote($this->getShopId());
3023  $iRemindActive = $oDb->quote($this->oxarticles__oxremindactive->value);
3024  $sUpdate = "
3025  update oxarticles
3026  set oxremindactive = $iRemindActive
3027  where oxparentid = $sOxId and
3028  oxshopid = $sOxShopId
3029  ";
3030  $oDb->execute($sUpdate);
3031  }
3032  }
3033 
3040  public function getProductId()
3041  {
3042  return $this->getId();
3043  }
3044 
3050  public function getParentId()
3051  {
3052  return $this->oxarticles__oxparentid->value;
3053  }
3054 
3060  public function isOrderArticle()
3061  {
3062  return false;
3063  }
3064 
3070  public function isVariant()
3071  {
3072  return (bool) (isset($this->oxarticles__oxparentid) ? $this->oxarticles__oxparentid->value : false);
3073  }
3074 
3080  public function isMdVariant()
3081  {
3082  $oMdVariant = oxNew("oxVariantHandler");
3083 
3084  return $oMdVariant->isMdVariant($this);
3085  }
3086 
3094  public function getSqlForPriceCategories($sFields = '')
3095  {
3096  if (!$sFields) {
3097  $sFields = 'oxid';
3098  }
3099  $sSelectWhere = "select $sFields from " . $this->_getObjectViewName('oxcategories') . " where";
3100  $sQuotedPrice = oxDb::getDb()->quote($this->oxarticles__oxprice->value);
3101 
3102  return "$sSelectWhere oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice"
3103  . " union $sSelectWhere oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice"
3104  . " union $sSelectWhere oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice";
3105  }
3106 
3114  public function inPriceCategory($sCatNid)
3115  {
3116  $oDb = oxDb::getDb();
3117 
3118  $sQuotedPrice = $oDb->quote($this->oxarticles__oxprice->value);
3119  $sQuotedCnid = $oDb->quote($sCatNid);
3120 
3121  return (bool) $oDb->getOne(
3122  "select 1 from " . $this->_getObjectViewName('oxcategories') . " where oxid=$sQuotedCnid and"
3123  . "( (oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice)"
3124  . " or (oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice)"
3125  . " or (oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice)"
3126  . ")"
3127  );
3128  }
3129 
3135  public function getMdVariants()
3136  {
3137  if ($this->_oMdVariants) {
3138  return $this->_oMdVariants;
3139  }
3140 
3141  $oParentArticle = $this->getParentArticle();
3142  if ($oParentArticle) {
3143  $oVariants = $oParentArticle->getVariants();
3144  } else {
3145  $oVariants = $this->getVariants();
3146  }
3147 
3148  $oVariantHandler = oxNew("oxVariantHandler");
3149  $this->_oMdVariants = $oVariantHandler->buildMdVariants($oVariants, $this->getId());
3150 
3151  return $this->_oMdVariants;
3152  }
3153 
3159  public function getMdSubvariants()
3160  {
3161  return $this->getMdVariants()->getMdSubvariants();
3162  }
3163 
3172  public function getPictureFieldValue($sFieldName, $iIndex = null)
3173  {
3174  if ($sFieldName) {
3175  $sFieldName = "oxarticles__" . $sFieldName . $iIndex;
3176 
3177  return $this->$sFieldName->value;
3178  }
3179  }
3180 
3188  public function getMasterZoomPictureUrl($iIndex)
3189  {
3190  $sPicUrl = false;
3191  $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
3192 
3193  if ($sPicName && $sPicName != "nopic.jpg") {
3194  $sPicUrl = $this->getConfig()->getPictureUrl("master/product/" . $iIndex . "/" . $sPicName);
3195  if (!$sPicUrl || basename($sPicUrl) == "nopic.jpg") {
3196  $sPicUrl = false;
3197  }
3198  }
3199 
3200  return $sPicUrl;
3201  }
3202 
3208  public function getUnitName()
3209  {
3210  if ($this->oxarticles__oxunitname->value) {
3211  return oxRegistry::getLang()->translateString($this->oxarticles__oxunitname->value);
3212  }
3213  }
3214 
3222  public function getArticleFiles($blAddFromParent = false)
3223  {
3224  if ($this->_aArticleFiles === null) {
3225 
3226  $this->_aArticleFiles = false;
3227 
3228  $sQ = "SELECT * FROM `oxfiles` WHERE `oxartid` = '" . $this->getId() . "'";
3229 
3230  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && $blAddFromParent) {
3231  $sQ .= " OR `oxartId` = '" . $this->oxarticles__oxparentid->value . "'";
3232  }
3233 
3234  $oArticleFiles = oxNew("oxlist");
3235  $oArticleFiles->init("oxfile");
3236  $oArticleFiles->selectString($sQ);
3237  $this->_aArticleFiles = $oArticleFiles;
3238 
3239  }
3240 
3241  return $this->_aArticleFiles;
3242  }
3243 
3249  public function isDownloadable()
3250  {
3251  return $this->oxarticles__oxisdownloadable->value;
3252  }
3253 
3259  public function hasAmountPrice()
3260  {
3261  if (self::$_blHasAmountPrice === null) {
3262 
3263  self::$_blHasAmountPrice = false;
3264 
3265  $oDb = oxDb::getDb();
3266  $sQ = "SELECT 1 FROM `oxprice2article` LIMIT 1";
3267 
3268  if ($oDb->getOne($sQ)) {
3269  self::$_blHasAmountPrice = true;
3270  }
3271  }
3272 
3273  return self::$_blHasAmountPrice;
3274  }
3275 
3285  protected function _loadVariantList($blSimple, $blRemoveNotOrderables = true, $blForceCoreTable = null)
3286  {
3287  $oVariants = array();
3288  if (($sId = $this->getId())) {
3289  //do not load me as a parent later
3290  self::$_aLoadedParents[$sId . "_" . $this->getLanguage()] = $this;
3291 
3292  $myConfig = $this->getConfig();
3293 
3294  if (!$this->_blLoadVariants ||
3295  (!$this->isAdmin() && !$myConfig->getConfigParam('blLoadVariants')) ||
3296  (!$this->isAdmin() && !$this->oxarticles__oxvarcount->value)
3297  ) {
3298  return $oVariants;
3299  }
3300 
3301  // cache
3302  $sCacheKey = $blSimple ? "simple" : "full";
3303  if ($blRemoveNotOrderables) {
3304  if (isset($this->_aVariants[$sCacheKey])) {
3305  return $this->_aVariants[$sCacheKey];
3306  } else {
3307  $this->_aVariants[$sCacheKey] = & $oVariants;
3308  }
3309  } elseif (!$blRemoveNotOrderables) {
3310  if (isset($this->_aVariantsWithNotOrderables[$sCacheKey])) {
3311  return $this->_aVariantsWithNotOrderables[$sCacheKey];
3312  } else {
3313  $this->_aVariantsWithNotOrderables[$sCacheKey] = & $oVariants;
3314  }
3315  }
3316 
3317  if (($this->_blHasVariants = $this->_hasAnyVariant($blForceCoreTable))) {
3318 
3319  //load simple variants for lists
3320  if ($blSimple) {
3321  $oVariants = oxNew('oxsimplevariantlist');
3322  $oVariants->setParent($this);
3323  } else {
3324  //loading variants
3325  $oVariants = oxNew('oxarticlelist');
3326  $oVariants->getBaseObject()->modifyCacheKey('_variants');
3327  }
3328 
3329  startProfile("selectVariants");
3330  $blUseCoreTable = (bool) $blForceCoreTable;
3331  $oBaseObject = $oVariants->getBaseObject();
3332  $oBaseObject->setLanguage($this->getLanguage());
3333 
3334 
3335  $sArticleTable = $this->getViewName($blUseCoreTable);
3336 
3337  $sSelect = "select " . $oBaseObject->getSelectFields($blUseCoreTable) . " from $sArticleTable where " .
3338  $this->getActiveCheckQuery($blUseCoreTable) .
3339  $this->getVariantsQuery($blRemoveNotOrderables, $blUseCoreTable) .
3340  " order by $sArticleTable.oxsort";
3341  $oVariants->selectString($sSelect);
3342 
3343  //if this is multidimensional variants, make additional processing
3344  if ($myConfig->getConfigParam('blUseMultidimensionVariants')) {
3345  $oMdVariants = oxNew("oxVariantHandler");
3346  $this->_blHasMdVariants = $oMdVariants->isMdVariant($oVariants->current());
3347  }
3348  stopProfile("selectVariants");
3349  }
3350 
3351  //if we have variants then depending on config option the parent may be non buyable
3352  if (!$myConfig->getConfigParam('blVariantParentBuyable') && $this->_blHasVariants) {
3353  $this->_blNotBuyableParent = true;
3354  }
3355 
3356  //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
3357  if (!$myConfig->getConfigParam('blVariantParentBuyable') && count($oVariants) == 0 && $this->_blHasVariants) {
3358  $this->_blNotBuyable = true;
3359  }
3360  }
3361 
3362  return $oVariants;
3363  }
3364 
3373  protected function _selectCategoryIds($sSql, $sField)
3374  {
3376  $aResult = $oDb->getAll($sSql);
3377  $aReturn = array();
3378 
3379 
3380  foreach ($aResult as $aValue) {
3381  $aValue = array_change_key_case($aValue, CASE_LOWER);
3382 
3383 
3384  $aReturn[] = $aValue[$sField];
3385  }
3386 
3387  return $aReturn;
3388  }
3389 
3397  protected function _getCategoryIdsSelect($blActCats = false)
3398  {
3399  $sO2CView = $this->_getObjectViewName('oxobject2category');
3400  $sCatView = $this->_getObjectViewName('oxcategories');
3401 
3402  $sArticleIdSql = 'oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getId());
3403  if ($this->getParentId()) {
3404  $sArticleIdSql = '(' . $sArticleIdSql . ' or oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getParentId()) . ')';
3405  }
3406  $sActiveCategorySql = $blActCats ? $this->_getActiveCategorySelectSnippet() : '';
3407 
3408  $sSelect = "select
3409  oxobject2category.oxcatnid as oxcatnid
3410  from $sO2CView as oxobject2category
3411  left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid
3412  where $sArticleIdSql and oxcategories.oxid is not null and oxcategories.oxactive = 1 $sActiveCategorySql
3413  order by oxobject2category.oxtime";
3414 
3415  return $sSelect;
3416  }
3417 
3423  protected function _getActiveCategorySelectSnippet()
3424  {
3425  $sCatView = $this->_getObjectViewName('oxcategories');
3426  $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 ";
3427 
3428  return $sActiveCategorySql;
3429  }
3430 
3441  protected function _getSelectCatIds($sOXID, $blActCats = false)
3442  {
3443  $sO2CView = $this->_getObjectViewName('oxobject2category');
3444  $sCatView = $this->_getObjectViewName('oxcategories');
3445  $sSelect = "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
3446  $sSelect .= 'where oxobject2category.oxobjectid=' . oxDb::getDb()->quote($sOXID) . ' and oxcategories.oxid is not null and oxcategories.oxactive = 1 ';
3447  if ($blActCats) {
3448  $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 ";
3449  }
3450  $sSelect .= 'order by oxobject2category.oxtime ';
3451 
3452  return $sSelect;
3453  }
3454 
3463  protected function _calculatePrice($oPrice, $dVat = null)
3464  {
3465  // apply VAT only if configuration requires it
3466  if (isset($dVat) || !$this->getConfig()->getConfigParam('bl_perfCalcVatOnlyForBasketOrder')) {
3467  $this->_applyVAT($oPrice, isset($dVat) ? $dVat : $this->getArticleVat());
3468  }
3469 
3470  // apply currency
3471  $this->_applyCurrency($oPrice);
3472  // apply discounts
3473  if (!$this->skipDiscounts()) {
3474  $oDiscountList = oxRegistry::get("oxDiscountList");
3475  $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
3476 
3477  reset($aDiscounts);
3478  foreach ($aDiscounts as $oDiscount) {
3479  $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
3480  }
3481  $oPrice->calculateDiscount();
3482  }
3483 
3484  return $oPrice;
3485  }
3486 
3494  protected function _hasAnyVariant($blForceCoreTable = null)
3495  {
3496  $blHas = false;
3497  if (($sId = $this->getId())) {
3498  if ($this->oxarticles__oxshopid->value == $this->getConfig()->getShopId()) {
3499  $blHas = (bool) $this->oxarticles__oxvarcount->value;
3500  } else {
3501  $sArticleTable = $this->getViewName($blForceCoreTable);
3502  $blHas = (bool) oxDb::getDb()->getOne("select 1 from $sArticleTable where oxparentid='{$sId}'");
3503  }
3504  }
3505 
3506  return $blHas;
3507  }
3508 
3514  protected function _isStockStatusChanged()
3515  {
3516  return $this->_iStockStatus != $this->_iStockStatusOnLoad;
3517  }
3518 
3524  protected function _isVisibilityChanged()
3525  {
3526  return $this->_isStockStatusChanged() && ($this->_iStockStatus == -1 || $this->_iStockStatusOnLoad == -1);
3527  }
3528 
3534  protected function _saveArtLongDesc()
3535  {
3536  $myConfig = $this->getConfig();
3537  $sShopId = $myConfig->getShopID();
3538  if (in_array("oxlongdesc", $this->_aSkipSaveFields)) {
3539  return;
3540  }
3541 
3542  if ($this->_blEmployMultilanguage) {
3543  $sValue = $this->getLongDescription()->getRawValue();
3544  if ($sValue !== null) {
3545  $oArtExt = oxNew('oxI18n');
3546  $oArtExt->init('oxartextends');
3547  $oArtExt->setLanguage((int) $this->getLanguage());
3548  if (!$oArtExt->load($this->getId())) {
3549  $oArtExt->setId($this->getId());
3550  }
3551  $oArtExt->oxartextends__oxlongdesc = new oxField($sValue, oxField::T_RAW);
3552  $oArtExt->save();
3553  }
3554  } else {
3555  $oArtExt = oxNew('oxI18n');
3556  $oArtExt->setEnableMultilang(false);
3557  $oArtExt->init('oxartextends');
3558  $aObjFields = $oArtExt->_getAllFields(true);
3559  if (!$oArtExt->load($this->getId())) {
3560  $oArtExt->setId($this->getId());
3561  }
3562 
3563  foreach ($aObjFields as $sKey => $sValue) {
3564  if (preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey)) {
3565  $sField = $this->_getFieldLongName($sKey);
3566 
3567  if (isset($this->$sField)) {
3568  $sLongDesc = null;
3569  if ($this->$sField instanceof oxField) {
3570  $sLongDesc = $this->$sField->getRawValue();
3571  } elseif (is_object($this->$sField)) {
3572  $sLongDesc = $this->$sField->value;
3573  }
3574  if (isset($sLongDesc)) {
3575  $sAEField = $oArtExt->_getFieldLongName($sKey);
3576  $oArtExt->$sAEField = new oxField($sLongDesc, oxField::T_RAW);
3577  }
3578  }
3579  }
3580  }
3581  $oArtExt->save();
3582  }
3583  }
3584 
3588  protected function _skipSaveFields()
3589  {
3590  $myConfig = $this->getConfig();
3591 
3592  $this->_aSkipSaveFields = array();
3593 
3594  $this->_aSkipSaveFields[] = 'oxtimestamp';
3595  // $this->_aSkipSaveFields[] = 'oxlongdesc';
3596  $this->_aSkipSaveFields[] = 'oxinsert';
3598 
3599  if (!$this->_blAllowEmptyParentId && (!isset($this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '')) {
3600  $this->_aSkipSaveFields[] = 'oxparentid';
3601  }
3602 
3603  }
3604 
3614  protected function _mergeDiscounts($aDiscounts, $aItemDiscounts)
3615  {
3616  foreach ($aItemDiscounts as $sKey => $oDiscount) {
3617  // add prices of the same discounts
3618  if (array_key_exists($sKey, $aDiscounts)) {
3619  $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
3620  } else {
3621  $aDiscounts[$sKey] = $oDiscount;
3622  }
3623  }
3624 
3625  return $aDiscounts;
3626  }
3627 
3633  protected function _getGroupPrice()
3634  {
3635  $sPriceSufix = $this->_getUserPriceSufix();
3636  $sVarName = "oxarticles__oxprice{$sPriceSufix}";
3637  $dPrice = $this->$sVarName->value;
3638 
3639  // #1437/1436C - added config option, and check for zero A,B,C price values
3640  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices') && (double) $dPrice == 0) {
3641  $dPrice = $this->oxarticles__oxprice->value;
3642  }
3643 
3644  return $dPrice;
3645  }
3646 
3655  protected function _getAmountPrice($dAmount = 1)
3656  {
3657  startProfile("_getAmountPrice");
3658 
3659  $dPrice = $this->_getGroupPrice();
3660  $oAmtPrices = $this->_getAmountPriceList();
3661  foreach ($oAmtPrices as $oAmPrice) {
3662  if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
3663  && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
3664  && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value
3665  ) {
3666  $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
3667  }
3668  }
3669 
3670  stopProfile("_getAmountPrice");
3671 
3672  return $dPrice;
3673  }
3674 
3683  protected function _modifySelectListPrice($dPrice, $aChosenList = null)
3684  {
3685  $myConfig = $this->getConfig();
3686  // #690
3687  if ($myConfig->getConfigParam('bl_perfLoadSelectLists') && $myConfig->getConfigParam('bl_perfUseSelectlistPrice')) {
3688 
3689  $aSelLists = $this->getSelectLists();
3690 
3691  foreach ($aSelLists as $key => $aSel) {
3692  if (isset($aChosenList[$key]) && isset($aSel[$aChosenList[$key]])) {
3693  $oSel = $aSel[$aChosenList[$key]];
3694  if ($oSel->priceUnit == 'abs') {
3695  $dPrice += $oSel->price;
3696  } elseif ($oSel->priceUnit == '%') {
3697  $dPrice += oxPrice::percent($dPrice, $oSel->price);
3698  }
3699  }
3700  }
3701  }
3702 
3703  return $dPrice;
3704  }
3705 
3713  protected function _fillAmountPriceList($aAmPriceList)
3714  {
3715  $oLang = oxRegistry::getLang();
3716 
3717  // trying to find lowest price value
3718  foreach ($aAmPriceList as $sId => $oItem) {
3719 
3720  $oItemPrice = $this->_getPriceObject();
3721  if ($oItem->oxprice2article__oxaddabs->value) {
3722 
3723  $dBasePrice = $oItem->oxprice2article__oxaddabs->value;
3724  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
3725 
3726  $oItemPrice->setPrice($dBasePrice);
3727  $this->_calculatePrice($oItemPrice);
3728 
3729  } else {
3730  $dBasePrice = $this->_getGroupPrice();
3731  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
3732  $oItemPrice->setPrice($dBasePrice);
3733  $oItemPrice->subtractPercent($oItem->oxprice2article__oxaddperc->value);
3734  }
3735 
3736 
3737  $aAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency($this->_getPriceForView($oItemPrice));
3738  }
3739 
3740  return $aAmPriceList;
3741  }
3742 
3750  public function getVariantIds($blActiveVariants = true)
3751  {
3752  $aSelect = array();
3753  $sId = $this->getId();
3754  if ($sId) {
3755  $sActiveSqlSnippet = "";
3756  if ($blActiveVariants) {
3757  $sActiveSqlSnippet = " and " . $this->getSqlActiveSnippet(true);
3758  }
3760  $sQ = "select oxid from " . $this->getViewName(true) . " where oxparentid = " . $oDb->quote($sId) .
3761  $sActiveSqlSnippet . " order by oxsort";
3762  $oRs = $oDb->select($sQ);
3763  if ($oRs != false && $oRs->recordCount() > 0) {
3764  while (!$oRs->EOF) {
3765  $aSelect[] = reset($oRs->fields);
3766  $oRs->moveNext();
3767  }
3768  }
3769  }
3770 
3771  return $aSelect;
3772  }
3773 
3783  protected function _getVariantsIds($blActiveVariants = true)
3784  {
3785  return $this->getVariantIds($blActiveVariants);
3786  }
3787 
3793  public function getArticleVat()
3794  {
3795  if (!isset($this->_dArticleVat)) {
3796  $this->_dArticleVat = oxRegistry::get("oxVatSelector")->getArticleVat($this);
3797  }
3798 
3799  return $this->_dArticleVat;
3800  }
3801 
3808  protected function _applyVAT(oxPrice $oPrice, $dVat)
3809  {
3810  startProfile(__FUNCTION__);
3811  $oPrice->setVAT($dVat);
3813  $oVatSelector = oxRegistry::get("oxVatSelector");
3814  if (($dVat = $oVatSelector->getArticleUserVat($this)) !== false) {
3815  $oPrice->setUserVat($dVat);
3816  }
3817  stopProfile(__FUNCTION__);
3818  }
3819 
3826  protected function _applyCurrency(oxPrice $oPrice, $oCur = null)
3827  {
3828  if (!$oCur) {
3829  $oCur = $this->getConfig()->getActShopCurrencyObject();
3830  }
3831 
3832  $oPrice->multiply($oCur->rate);
3833  }
3834 
3835 
3842  protected function _getAttribsString(&$sAttributeSql, &$iCnt)
3843  {
3844  // we do not use lists here as we don't need this overhead right now
3845  $oDb = oxDb::getDb();
3846  $sSelect = 'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid=' . $oDb->quote($this->getId());
3847  if ($this->getParentId()) {
3848  $sSelect .= ' OR oxobject2attribute.oxobjectid=' . $oDb->quote($this->getParentId());
3849  }
3850  $sAttributeSql = '';
3851  $aAttributeIds = $oDb->getCol($sSelect);
3852  if (is_array($aAttributeIds) && count($aAttributeIds)) {
3853  $aAttributeIds = array_unique($aAttributeIds);
3854  $iCnt = count($aAttributeIds);
3855  $sAttributeSql .= 't1.oxattrid IN ( ' . implode(',', $oDb->quoteArray($aAttributeIds)) . ') ';
3856  }
3857  }
3858 
3867  protected function _getSimList($sAttributeSql, $iCnt)
3868  {
3869  // #523A
3870  $iAttrPercent = $this->getConfig()->getConfigParam('iAttributesPercent') / 100;
3871  // 70% same attributes
3872  if (!$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
3873  $iAttrPercent = 0.70;
3874  }
3875  // #1137V iAttributesPercent = 100 doesn't work
3876  $iHitMin = ceil($iCnt * $iAttrPercent);
3877 
3878  $aExcludeIds = array();
3879  $aExcludeIds[] = $this->getId();
3880  if ($this->getParentId()) {
3881  $aExcludeIds[] = $this->getParentId();
3882  }
3883 
3884  // we do not use lists here as we don't need this overhead right now
3885  $sSelect = "select oxobjectid from oxobject2attribute as t1 where
3886  ( $sAttributeSql )
3887  and t1.oxobjectid NOT IN (" . implode(', ', oxDb::getDb()->quoteArray($aExcludeIds)) . ")
3888  group by t1.oxobjectid having count(*) >= $iHitMin LIMIT 0, 20";
3889 
3890  return oxDb::getDb()->getCol($sSelect);
3891  }
3892 
3901  protected function _generateSimListSearchStr($sArticleTable, $aList)
3902  {
3903  $sFieldList = $this->getSelectFields();
3904  $aList = array_slice($aList, 0, $this->getConfig()->getConfigParam('iNrofSimilarArticles'));
3905 
3906  $sSearch = "select $sFieldList from $sArticleTable where " . $this->getSqlActiveSnippet() . " and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
3907 
3908  $sSearch .= implode(',', oxdb::getDb()->quoteArray($aList)) . ')';
3909 
3910  // #524A -- randomizing articles in attribute list
3911  $sSearch .= ' order by rand() ';
3912 
3913  return $sSearch;
3914  }
3915 
3924  protected function _generateSearchStr($sOXID, $blSearchPriceCat = false)
3925  {
3926 
3927  $sCatView = getViewName('oxcategories', $this->getLanguage());
3928  $sO2CView = getViewName('oxobject2category');
3929 
3930  // we do not use lists here as we don't need this overhead right now
3931  if (!$blSearchPriceCat) {
3932  $sSelect = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
3933  {$sCatView}.oxid = oxobject2category.oxcatnid
3934  where oxobject2category.oxobjectid=" . oxDb::getDb()->quote($sOXID) . " and {$sCatView}.oxid is not null ";
3935  } else {
3936  $sSelect = "select {$sCatView}.* from {$sCatView} where
3937  '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
3938  '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
3939  }
3940 
3941  return $sSelect;
3942  }
3943 
3950  {
3951  $sArtTable = $this->getViewName();
3952  $sOrderArtTable = getViewName('oxorderarticles');
3953 
3954  // fetching filter params
3955  $sIn = " '{$this->oxarticles__oxid->value}' ";
3956  if ($this->oxarticles__oxparentid->value) {
3957 
3958  // adding article parent
3959  $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
3960  $sParentIdForVariants = $this->oxarticles__oxparentid->value;
3961 
3962  } else {
3963  $sParentIdForVariants = $this->getId();
3964  }
3965 
3966  // adding variants
3968  $oRs = $oDb->select("select oxid from {$sArtTable} where oxparentid = " . $oDb->quote($sParentIdForVariants) . " and oxid != " . $oDb->quote($this->oxarticles__oxid->value));
3969  if ($oRs != false && $oRs->recordCount() > 0) {
3970  while (!$oRs->EOF) {
3971  $sIn .= ", " . $oDb->quote(current($oRs->fields)) . " ";
3972  $oRs->moveNext();
3973  }
3974  }
3975 
3976  $iLimit = (int) $this->getConfig()->getConfigParam('iNrofCustomerWhoArticles');
3977  $iLimit = $iLimit ? ($iLimit * 10) : 50;
3978 
3979  // building sql (optimized)
3980  $sQ = "select distinct {$sArtTable}.* from (
3981  select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
3982  ) as suborder
3983  left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
3984  left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
3985  where {$sArtTable}.oxid not in ( {$sIn} )
3986  and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and " . $this->getSqlActiveSnippet();
3987 
3988  /* non optimized, but could be used if index forcing is not supported
3989  // building sql
3990  $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
3991  select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
3992  ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
3993  and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
3994  and ".$this->getSqlActiveSnippet();
3995  */
3996 
3997  return $sQ;
3998  }
3999 
4009  protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
4010  {
4011  $sCategoryView = getViewName('oxcategories');
4012  $sO2CView = getViewName('oxobject2category');
4013 
4014  $oDb = oxDb::getDb();
4015  $sOXID = $oDb->quote($sOXID);
4016  $sCatId = $oDb->quote($sCatId);
4017 
4018  if (!$dPriceFromTo) {
4019  $sSelect = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
4020  $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
4021  $sSelect .= "where oxobject2category.oxcatnid=$sCatId and oxobject2category.oxobjectid=$sOXID ";
4022  $sSelect .= "and oxcategories.oxactive = 1 order by oxobject2category.oxtime ";
4023  } else {
4024  $dPriceFromTo = $oDb->quote($dPriceFromTo);
4025  $sSelect = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
4026  $sSelect .= "oxcategories.oxid=$sCatId and $dPriceFromTo >= oxcategories.oxpricefrom and ";
4027  $sSelect .= "$dPriceFromTo <= oxcategories.oxpriceto ";
4028  }
4029 
4030  return $sSelect;
4031  }
4032 
4038  protected function _getAmountPriceList()
4039  {
4040  if ($this->_oAmountPriceList === null) {
4041  $oAmPriceList = oxNew('oxAmountPricelist');
4042 
4043  if (!$this->skipDiscounts()) {
4044  //collecting assigned to article amount-price list
4045  $oAmPriceList->load($this);
4046 
4047  // prepare abs prices if currently having percentages
4048  $oBasePrice = $this->_getGroupPrice();
4049  foreach ($oAmPriceList as $oAmPrice) {
4050  if ($oAmPrice->oxprice2article__oxaddperc->value) {
4051  $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent($oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value), oxField::T_RAW);
4052  }
4053  }
4054 
4055  }
4056 
4057  $this->_oAmountPriceList = $oAmPriceList;
4058  }
4059 
4060  return $this->_oAmountPriceList;
4061  }
4062 
4070  protected function _isFieldEmpty($sFieldName)
4071  {
4072  $mValue = $this->$sFieldName->value;
4073 
4074  if (is_null($mValue)) {
4075  return true;
4076  }
4077 
4078  if ($mValue === '') {
4079  return true;
4080  }
4081 
4082  // certain fields with zero value treat as empty
4083  $aZeroValueFields = array('oxarticles__oxprice', 'oxarticles__oxvat', 'oxarticles__oxunitquantity');
4084 
4085  if (!$mValue && in_array($sFieldName, $aZeroValueFields)) {
4086  return true;
4087  }
4088 
4089 
4090  if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
4091  return true;
4092  }
4093 
4094  $sFieldName = strtolower($sFieldName);
4095 
4096  if ($sFieldName == 'oxarticles__oxicon' && (strpos($mValue, "nopic_ico.jpg") !== false || strpos($mValue, "nopic.jpg") !== false)) {
4097  return true;
4098  }
4099 
4100  if (strpos($mValue, "nopic.jpg") !== false && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom')) {
4101  return true;
4102  }
4103 
4104  return false;
4105  }
4106 
4114  protected function _assignParentFieldValue($sFieldName)
4115  {
4116  if (!($oParentArticle = $this->getParentArticle())) {
4117  return;
4118  }
4119 
4120  $sCopyFieldName = $this->_getFieldLongName($sFieldName);
4121 
4122  // assigning only these which parent article has
4123  if ($oParentArticle->$sCopyFieldName != null) {
4124 
4125  // only overwrite database values
4126  if (substr($sCopyFieldName, 0, 12) != 'oxarticles__') {
4127  return;
4128  }
4129 
4130  //do not copy certain fields
4131  if (in_array($sCopyFieldName, $this->_aNonCopyParentFields)) {
4132  return;
4133  }
4134 
4135  //skip picture parent value assignment in case master image is set for variant
4136  if ($this->_isFieldEmpty($sCopyFieldName) && $this->_isImageField($sCopyFieldName) && $this->_hasMasterImage(1)) {
4137  return;
4138  }
4139 
4140  //COPY THE VALUE
4141  if ($this->_isFieldEmpty($sCopyFieldName)) {
4142  $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
4143  }
4144  }
4145  }
4146 
4154  protected function _isImageField($sFieldName)
4155  {
4156  $blIsImageField = (stristr($sFieldName, '_oxthumb') || stristr($sFieldName, '_oxicon') || stristr($sFieldName, '_oxzoom') || stristr($sFieldName, '_oxpic'));
4157 
4158  return $blIsImageField;
4159  }
4160 
4164  protected function _assignParentFieldValues()
4165  {
4166  startProfile('articleAssignParentInternal');
4167  if ($this->oxarticles__oxparentid->value) {
4168  // yes, we are in fact a variant
4169  if (!$this->isAdmin() || ($this->_blLoadParentData && $this->isAdmin())) {
4170  foreach ($this->_aFieldNames as $sFieldName => $sVal) {
4171  $this->_assignParentFieldValue($sFieldName);
4172  }
4173  }
4174  }
4175  stopProfile('articleAssignParentInternal');
4176  }
4177 
4181  protected function _assignNotBuyableParent()
4182  {
4183  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') &&
4184  ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value)
4185  ) {
4186  $this->_blNotBuyableParent = true;
4187 
4188  }
4189  }
4190 
4194  protected function _assignStock()
4195  {
4196  $myConfig = $this->getConfig();
4197  // -----------------------------------
4198  // stock
4199  // -----------------------------------
4200 
4201  // #1125 A. must round (using floor()) value taken from database and cast to int
4202  if (!$myConfig->getConfigParam('blAllowUnevenAmounts') && !$this->isAdmin()) {
4203  $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
4204  }
4205  //GREEN light
4206  $this->_iStockStatus = 0;
4207 
4208  // if we have flag /*1 or*/ 4 - we show always green light
4209  if ($myConfig->getConfigParam('blUseStock') && /*$this->oxarticles__oxstockflag->value != 1 && */
4210  $this->oxarticles__oxstockflag->value != 4
4211  ) {
4212  //ORANGE light
4213  $iStock = $this->oxarticles__oxstock->value;
4214 
4215  if ($this->_blNotBuyableParent) {
4216  $iStock = $this->oxarticles__oxvarstock->value;
4217  }
4218 
4219 
4220  if ($iStock <= $myConfig->getConfigParam('sStockWarningLimit') && $iStock > 0) {
4221  $this->_iStockStatus = 1;
4222  }
4223 
4224  //RED light
4225  if ($iStock <= 0) {
4226  $this->_iStockStatus = -1;
4227  }
4228  }
4229 
4230 
4231  // stock
4232  if ($myConfig->getConfigParam('blUseStock') && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
4233  $iOnStock = $this->oxarticles__oxstock->value;
4234  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
4235  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
4236  }
4237  if ($iOnStock <= 0) {
4238  $this->setBuyableState(false);
4239  }
4240  }
4241 
4242  //exceptional handling for variant parent stock:
4243  if ($this->_blNotBuyable && $this->oxarticles__oxvarstock->value) {
4244  $this->setBuyableState(true);
4245  //but then at least setting notBuaybleParent to true
4246  $this->_blNotBuyableParent = true;
4247  }
4248 
4249  //special treatment for lists when blVariantParentBuyable config option is set to false
4250  //then we just hide "to basket" button.
4251  //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
4252  if (!$myConfig->getConfigParam('blVariantParentBuyable') && !$myConfig->getConfigParam('blLoadVariants') && $this->oxarticles__oxvarstock->value) {
4253  $this->setBuyableState(false);
4254  }
4255 
4256  //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
4257  if (!$this->_blNotBuyable && $this->_blNotBuyableParent && $this->oxarticles__oxvarcount->value == 0) {
4258  $this->setBuyableState(false);
4259  }
4260  }
4261 
4265  protected function _assignPersistentParam()
4266  {
4267  // Persistent Parameter Handling
4268  $aPersParam = oxRegistry::getSession()->getVariable('persparam');
4269  if (isset($aPersParam) && isset($aPersParam[$this->getId()])) {
4270  $this->_aPersistParam = $aPersParam[$this->getId()];
4271  }
4272  }
4273 
4277  protected function _assignDynImageDir()
4278  {
4279  $myConfig = $this->getConfig();
4280 
4281  $sThisShop = $this->oxarticles__oxshopid->value;
4282 
4283  $this->_sDynImageDir = $myConfig->getPictureUrl(null, false);
4284  $this->dabsimagedir = $myConfig->getPictureDir(false); //$sThisShop
4285  $this->nossl_dimagedir = $myConfig->getPictureUrl(null, false, false, null, $sThisShop); //$sThisShop
4286  $this->ssl_dimagedir = $myConfig->getPictureUrl(null, false, true, null, $sThisShop); //$sThisShop
4287  }
4288 
4292  protected function _assignComparisonListFlag()
4293  {
4294  // #657 add a flag if article is on comparisonlist
4295 
4296  $aItems = oxRegistry::getSession()->getVariable('aFiltcompproducts');
4297  if (isset($aItems[$this->getId()])) {
4298  $this->_blIsOnComparisonList = true;
4299  }
4300  }
4301 
4309  protected function _insert()
4310  {
4311  // set oxinsert
4312  $sNow = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
4313  $this->oxarticles__oxinsert = new oxField($sNow);
4314  if (!is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
4315  $this->oxarticles__oxsubclass = new oxField('oxarticle');
4316  }
4317 
4318  $blRes = parent::_insert();
4319 
4320 
4321  return $blRes;
4322  }
4323 
4329  protected function _update()
4330  {
4331 
4332  $this->setUpdateSeo(true);
4333  $this->_setUpdateSeoOnFieldChange('oxtitle');
4334 
4335  $this->_skipSaveFields();
4336 
4337  $myConfig = $this->getConfig();
4338 
4339 
4340  $blRes = parent::_update();
4341 
4342 
4343  return $blRes;
4344  }
4345 
4353  protected function _deleteRecords($sOXID)
4354  {
4355  $oDb = oxDb::getDb();
4356 
4357  $sOXID = $oDb->quote($sOXID);
4358 
4359  //remove other records
4360  $sDelete = 'delete from oxobject2article where oxarticlenid = ' . $sOXID . ' or oxobjectid = ' . $sOXID . ' ';
4361  $oDb->execute($sDelete);
4362 
4363  $sDelete = 'delete from oxobject2attribute where oxobjectid = ' . $sOXID . ' ';
4364  $oDb->execute($sDelete);
4365 
4366  $sDelete = 'delete from oxobject2category where oxobjectid = ' . $sOXID . ' ';
4367  $oDb->execute($sDelete);
4368 
4369  $sDelete = 'delete from oxobject2selectlist where oxobjectid = ' . $sOXID . ' ';
4370  $oDb->execute($sDelete);
4371 
4372  $sDelete = 'delete from oxprice2article where oxartid = ' . $sOXID . ' ';
4373  $oDb->execute($sDelete);
4374 
4375  $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = ' . $sOXID . ' ';
4376  $oDb->execute($sDelete);
4377 
4378  $sDelete = 'delete from oxratings where oxobjectid = ' . $sOXID . ' ';
4379  $rs = $oDb->execute($sDelete);
4380 
4381  $sDelete = 'delete from oxaccessoire2article where oxobjectid = ' . $sOXID . ' or oxarticlenid = ' . $sOXID . ' ';
4382  $oDb->execute($sDelete);
4383 
4384  //#1508C - deleting oxobject2delivery entries added
4385  $sDelete = 'delete from oxobject2delivery where oxobjectid = ' . $sOXID . ' and oxtype=\'oxarticles\' ';
4386  $oDb->execute($sDelete);
4387 
4388  $sDelete = 'delete from oxartextends where oxid = ' . $sOXID . ' ';
4389  $oDb->execute($sDelete);
4390 
4391  //delete the record
4392  foreach ($this->_getLanguageSetTables("oxartextends") as $sSetTbl) {
4393  $oDb->execute("delete from $sSetTbl where oxid = {$sOXID}");
4394  }
4395 
4396  $sDelete = 'delete from oxactions2article where oxartid = ' . $sOXID . ' ';
4397  $rs = $oDb->execute($sDelete);
4398 
4399  $sDelete = 'delete from oxobject2list where oxobjectid = ' . $sOXID . ' ';
4400  $rs = $oDb->execute($sDelete);
4401 
4402 
4403  return $rs;
4404  }
4405 
4411  protected function _deleteVariantRecords($sOXID)
4412  {
4413  if ($sOXID) {
4414  $oDb = oxDb::getDb();
4415  //collect variants to remove recursively
4416  $sQ = 'select oxid from ' . $this->getViewName() . ' where oxparentid = ' . $oDb->quote($sOXID);
4417  $rs = $oDb->select($sQ, false, false);
4418  $oArticle = oxNew("oxArticle");
4419  if ($rs != false && $rs->recordCount() > 0) {
4420  while (!$rs->EOF) {
4421  $oArticle->setId($rs->fields[0]);
4422  $oArticle->delete();
4423  $rs->moveNext();
4424  }
4425  }
4426  }
4427  }
4428 
4432  protected function _deletePics()
4433  {
4434  $myUtilsPic = oxRegistry::get("oxUtilsPic");
4435  $myConfig = $this->getConfig();
4436  $oPictureHandler = oxRegistry::get("oxPictureHandler");
4437 
4438  //deleting custom main icon
4439  $oPictureHandler->deleteMainIcon($this);
4440 
4441  //deleting custom thumbnail
4442  $oPictureHandler->deleteThumbnail($this);
4443 
4444  $sAbsDynImageDir = $myConfig->getPictureDir(false);
4445 
4446  // deleting master image and all generated images
4447  $iPicCount = $myConfig->getConfigParam('iPicCount');
4448  for ($i = 1; $i <= $iPicCount; $i++) {
4449  $oPictureHandler->deleteArticleMasterPicture($this, $i);
4450  }
4451  }
4452 
4460  protected function _onChangeResetCounts($sOxid, $sVendorId = null, $sManufacturerId = null)
4461  {
4462  $myUtilsCount = oxRegistry::get("oxUtilsCount");
4463 
4464  if ($sVendorId) {
4465  $myUtilsCount->resetVendorArticleCount($sVendorId);
4466  }
4467 
4468  if ($sManufacturerId) {
4469  $myUtilsCount->resetManufacturerArticleCount($sManufacturerId);
4470  }
4471 
4472  $aCategoryIds = $this->getCategoryIds();
4473  //also reseting category counts
4474  foreach ($aCategoryIds as $sCatId) {
4475  $myUtilsCount->resetCatArticleCount($sCatId, false);
4476  }
4477  }
4478 
4484  protected function _onChangeUpdateStock($sParentID)
4485  {
4486  if ($sParentID) {
4487  $oDb = oxDb::getDb();
4488  $sParentIdQuoted = $oDb->quote($sParentID);
4489  $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = ' . $sParentIdQuoted;
4490  $rs = $oDb->select($sQ, false, false);
4491  $iOldStock = $rs->fields[0];
4492  $iVendorID = $rs->fields[1];
4493  $iManufacturerID = $rs->fields[2];
4494 
4495  $sQ = 'select sum(oxstock) from ' . $this->getViewName(true) . ' where oxparentid = ' . $sParentIdQuoted . ' and ' . $this->getSqlActiveSnippet(true) . ' and oxstock > 0 ';
4496  $iStock = (float) $oDb->getOne($sQ, false, false);
4497 
4498  $sQ = 'update oxarticles set oxvarstock = ' . $iStock . ' where oxid = ' . $sParentIdQuoted;
4499  $oDb->execute($sQ);
4500 
4501  //now lets update category counts
4502  //first detect stock status change for this article (to or from 0)
4503  if ($iStock < 0) {
4504  $iStock = 0;
4505  }
4506  if ($iOldStock < 0) {
4507  $iOldStock = 0;
4508  }
4509  if ($this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock) {
4510  //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
4511  // so far we leave it like this but later we could move all count resets to one or two functions
4512  $this->_onChangeResetCounts($sParentID, $iVendorID, $iManufacturerID);
4513  }
4514  }
4515  }
4516 
4522  protected function _onChangeStockResetCount($sOxid)
4523  {
4524  $myConfig = $this->getConfig();
4525 
4526  if ($myConfig->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2 &&
4527  ($this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value) <= 0
4528  ) {
4529 
4530  $this->_onChangeResetCounts($sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
4531  }
4532  }
4533 
4539  protected function _onChangeUpdateVarCount($sParentID)
4540  {
4541  if ($sParentID) {
4542  $oDb = oxDb::getDb();
4543  $sParentIdQuoted = $oDb->quote($sParentID);
4544  $sQ = "select count(*) as varcount from oxarticles where oxparentid = {$sParentIdQuoted}";
4545  $iVarCount = (int) $oDb->getOne($sQ, false, false);
4546 
4547  $sQ = "update oxarticles set oxvarcount = {$iVarCount} where oxid = {$sParentIdQuoted}";
4548  $oDb->execute($sQ);
4549  }
4550  }
4551 
4557  protected function _setVarMinMaxPrice($sParentId)
4558  {
4559  if ($sParentId) {
4561  $sQ = '
4562  SELECT
4563  MIN( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varminprice`,
4564  MAX( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varmaxprice`
4565  FROM ' . $this->getViewName(true) . ' AS `oxarticles`
4566  LEFT JOIN ' . $this->getViewName(true) . ' AS `p` ON ( `p`.`oxid` = `oxarticles`.`oxparentid` AND `p`.`oxprice` > 0 )
4567  WHERE ' . $this->getSqlActiveSnippet(true) . '
4568  AND ( `oxarticles`.`oxparentid` = ' . $oDb->quote($sParentId) . ' )';
4569  $oDb->setFetchMode(oxDb::FETCH_MODE_ASSOC);
4570  $aPrices = $oDb->getRow($sQ, false, false);
4571  if (!is_null($aPrices['varminprice']) || !is_null($aPrices['varmaxprice'])) {
4572  $sQ = '
4573  UPDATE `oxarticles`
4574  SET
4575  `oxvarminprice` = ' . $oDb->quote($aPrices['varminprice']) . ',
4576  `oxvarmaxprice` = ' . $oDb->quote($aPrices['varmaxprice']) . '
4577  WHERE
4578  `oxid` = ' . $oDb->quote($sParentId);
4579  } else {
4580  $sQ = '
4581  UPDATE `oxarticles`
4582  SET
4583  `oxvarminprice` = `oxprice`,
4584  `oxvarmaxprice` = `oxprice`
4585  WHERE
4586  `oxid` = ' . $oDb->quote($sParentId);
4587  }
4588  $oDb->execute($sQ);
4589  }
4590  }
4591 
4599  protected function _hasMasterImage($iIndex)
4600  {
4601  $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
4602 
4603  if ($sPicName == "nopic.jpg" || $sPicName == "") {
4604  return false;
4605  }
4606  if ($this->isVariant() &&
4607  $this->getParentArticle() &&
4608  $this->getParentArticle()->{"oxarticles__oxpic" . $iIndex}->value == $this->{"oxarticles__oxpic" . $iIndex}->value
4609  ) {
4610  return false;
4611  }
4612 
4613  $sMasterPic = 'product/' . $iIndex . "/" . $sPicName;
4614 
4615  if ($this->getConfig()->getMasterPicturePath($sMasterPic)) {
4616  return true;
4617  }
4618 
4619  return false;
4620  }
4621 
4627  protected function _isPriceViewModeNetto()
4628  {
4629  $blResult = (bool) $this->getConfig()->getConfigParam('blShowNetPrice');
4630  $oUser = $this->getArticleUser();
4631  if ($oUser) {
4632  $blResult = $oUser->isPriceViewModeNetto();
4633  }
4634 
4635  return $blResult;
4636  }
4637 
4638 
4646  protected function _getPriceObject($blCalculationModeNetto = null)
4647  {
4648  $oPrice = oxNew('oxPrice');
4649 
4650  if ($blCalculationModeNetto === null) {
4651  $blCalculationModeNetto = $this->_isPriceViewModeNetto();
4652  }
4653 
4654  if ($blCalculationModeNetto) {
4655  $oPrice->setNettoPriceMode();
4656  } else {
4657  $oPrice->setBruttoPriceMode();
4658  }
4659 
4660  return $oPrice;
4661  }
4662 
4663 
4671  protected function _getPriceForView($oPrice)
4672  {
4673  if ($this->_isPriceViewModeNetto()) {
4674  $dPrice = $oPrice->getNettoPrice();
4675  } else {
4676  $dPrice = $oPrice->getBruttoPrice();
4677  }
4678 
4679  return $dPrice;
4680  }
4681 
4682 
4692  protected function _preparePrice($dPrice, $dVat, $blCalculationModeNetto = null)
4693  {
4694  if ($blCalculationModeNetto === null) {
4695  $blCalculationModeNetto = $this->_isPriceViewModeNetto();
4696  }
4697 
4698  $oCurrency = $this->getConfig()->getActShopCurrencyObject();
4699 
4700  $blEnterNetPrice = $this->getConfig()->getConfigParam('blEnterNetPrice');
4701  if ($blCalculationModeNetto && !$blEnterNetPrice) {
4702  $dPrice = round(oxPrice::brutto2Netto($dPrice, $dVat), $oCurrency->decimal);
4703  } elseif (!$blCalculationModeNetto && $blEnterNetPrice) {
4704  $dPrice = round(oxPrice::netto2Brutto($dPrice, $dVat), $oCurrency->decimal);
4705  }
4706 
4707  return $dPrice;
4708  }
4709 
4715  protected function _getUserPriceSufix()
4716  {
4717  $sPriceSuffix = '';
4718  $oUser = $this->getArticleUser();
4719 
4720  if ($oUser) {
4721  if ($oUser->inGroup('oxidpricea')) {
4722  $sPriceSuffix = 'a';
4723  } elseif ($oUser->inGroup('oxidpriceb')) {
4724  $sPriceSuffix = 'b';
4725  } elseif ($oUser->inGroup('oxidpricec')) {
4726  $sPriceSuffix = 'c';
4727  }
4728  }
4729 
4730  return $sPriceSuffix;
4731  }
4732 
4733 
4739  protected function _getPrice()
4740  {
4741  $sPriceSuffix = $this->_getUserPriceSufix();
4742  if ($sPriceSuffix === '') {
4743  $dPrice = $this->oxarticles__oxprice->value;
4744  } else {
4745  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4746  $dPrice = ($this->{oxarticles__oxprice . $sPriceSuffix}->value != 0) ? $this->{oxarticles__oxprice . $sPriceSuffix}->value : $this->oxarticles__oxprice->value;
4747  } else {
4748  $dPrice = $this->{oxarticles__oxprice . $sPriceSuffix}->value;
4749  }
4750  }
4751 
4752  return $dPrice;
4753  }
4754 
4755 
4761  protected function _getVarMinPrice()
4762  {
4763  if ($this->_dVarMinPrice === null) {
4764  $dPrice = null;
4765 
4766 
4767  if (is_null($dPrice)) {
4768  $sPriceSuffix = $this->_getUserPriceSufix();
4769  if ($sPriceSuffix === '') {
4770  $dPrice = $this->oxarticles__oxvarminprice->value;
4771  } else {
4772  $sSql = 'SELECT ';
4773  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4774  $sSql .= 'MIN( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varminprice` ';
4775  } else {
4776  $sSql .= 'MIN(`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
4777  }
4778 
4779  $sSql .= ' FROM ' . $this->getViewName(true) . '
4780  WHERE ' . $this->getSqlActiveSnippet(true) . '
4781  AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
4782 
4783  $dPrice = oxDb::getDb()->getOne($sSql);
4784  }
4785  }
4786 
4787  $this->_dVarMinPrice = $dPrice;
4788  }
4789 
4790  return $this->_dVarMinPrice;
4791  }
4792 
4798  protected function _getSubShopVarMinPrice()
4799  {
4800  $myConfig = $this->getConfig();
4801  $sShopId = $myConfig->getShopId();
4802  if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
4803  $sPriceSuffix = $this->_getUserPriceSufix();
4804  $sSql = 'SELECT ';
4805  if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4806  $sSql .= 'MIN(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varminprice` ';
4807  } else {
4808  $sSql .= 'MIN(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
4809  }
4810  $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
4811  INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
4812  WHERE ' . $this->getSqlActiveSnippet(true) . '
4813  AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
4814  AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
4815  $dPrice = oxDb::getDb()->getOne($sSql);
4816  }
4817 
4818  return $dPrice;
4819  }
4820 
4826  protected function _getVarMaxPrice()
4827  {
4828  if ($this->_dVarMaxPrice === null) {
4829 
4830  $dPrice = null;
4831 
4832  if (is_null($dPrice)) {
4833  $sPriceSuffix = $this->_getUserPriceSufix();
4834  if ($sPriceSuffix === '') {
4835  $dPrice = $this->oxarticles__oxvarmaxprice->value;
4836  } else {
4837  $sSql = 'SELECT ';
4838  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4839  $sSql .= 'MAX( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varmaxprice` ';
4840  } else {
4841  $sSql .= 'MAX(`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
4842  }
4843 
4844  $sSql .= ' FROM ' . $this->getViewName(true) . '
4845  WHERE ' . $this->getSqlActiveSnippet(true) . '
4846  AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
4847 
4848  $dPrice = oxDb::getDb()->getOne($sSql);
4849  }
4850  }
4851 
4852  $this->_dVarMaxPrice = $dPrice;
4853  }
4854 
4855  return $this->_dVarMaxPrice;
4856  }
4857 
4863  protected function _getSubShopVarMaxPrice()
4864  {
4865  $myConfig = $this->getConfig();
4866  $sShopId = $myConfig->getShopId();
4867  if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
4868  $sPriceSuffix = $this->_getUserPriceSufix();
4869  $sSql = 'SELECT ';
4870  if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4871  $sSql .= 'MAX(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varmaxprice` ';
4872  } else {
4873  $sSql .= 'MAX(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
4874  }
4875  $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
4876  INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
4877  WHERE ' . $this->getSqlActiveSnippet(true) . '
4878  AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
4879  AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
4880  $dPrice = oxDb::getDb()->getOne($sSql);
4881  }
4882 
4883  return $dPrice;
4884  }
4885 
4893  protected function _loadFromDb($sOXID)
4894  {
4895 
4896  $sSelect = $this->buildSelectString(array($this->getViewName() . ".oxid" => $sOXID));
4897 
4898 
4899  $aData = oxDb::getDb(oxDb::FETCH_MODE_ASSOC)->getRow($sSelect);
4900 
4901  return $aData;
4902  }
4903 
4909  protected function _updateParentDependFields()
4910  {
4911  $oDb = oxDb::getDb();
4912 
4913  foreach ($this->_getCopyParentFields() as $sField) {
4914  $sValue = isset($this->$sField->value) ? $this->$sField->value : 0;
4915  $sSqlSets[] = '`' . str_replace('oxarticles__', '', $sField) . '` = ' . $oDb->quote($sValue);
4916  }
4917 
4918  $sSql = "UPDATE `oxarticles` SET ";
4919  $sSql .= implode(', ', $sSqlSets) . '';
4920  $sSql .= " WHERE `oxparentid` = " . $oDb->quote($this->getId());
4921 
4922  return $oDb->execute($sSql);
4923  }
4924 
4925 
4931  protected function _getCopyParentFields()
4932  {
4933  return $this->_aCopyParentField;
4934  }
4935 
4939  protected function _assignParentDependFields()
4940  {
4941  $sParent = $this->getParentArticle();
4942  if ($sParent) {
4943  foreach ($this->_getCopyParentFields() as $sField) {
4944  $this->$sField = new oxField($sParent->$sField->value);
4945  }
4946  }
4947  }
4948 
4949 
4950 
4954  protected function _saveSortingFieldValuesOnLoad()
4955  {
4956  $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
4957  $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
4958 
4959  foreach ($aSortingFields as $sField) {
4960  $sFullField = $this->_getFieldLongName($sField);
4961  $this->_aSortingFieldsOnLoad[$sFullField] = $this->$sFullField->value;
4962  }
4963  }
4964 }