OXID eShop CE  4.10.7
 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  $oDb = oxDb::getDb();
2075  $sQuery = 'select oxstock from oxarticles where oxid = ' . $oDb->quote($this->getId()) . ' FOR UPDATE ';
2076  $actualStock = $oDb->getOne($sQuery);
2077 
2078  $iStockCount = $actualStock - $dAmount;
2079  if (!$blAllowNegativeStock && ($iStockCount < 0)) {
2080  $dAmount += $iStockCount;
2081  $iStockCount = 0;
2082  }
2083  $this->oxarticles__oxstock = new oxField($iStockCount);
2084 
2085  $sQuery = 'update oxarticles set oxarticles.oxstock = ' . $oDb->quote($iStockCount) .
2086  ' where oxarticles.oxid = ' . $oDb->quote($this->getId());
2087  $oDb->execute($sQuery);
2088  $this->onChange(ACTION_UPDATE_STOCK);
2089 
2090  return $dAmount;
2091  }
2092 
2101  public function updateSoldAmount($dAmount = 0)
2102  {
2103  if (!$dAmount) {
2104  return;
2105  }
2106 
2107  // article is not variant - should be updated current amount
2108  if (!$this->oxarticles__oxparentid->value) {
2109  //updating by SQL query, due to wrong behaviour if saving article using not admin mode
2110  $dAmount = (double) $dAmount;
2111  $oDb = oxDb::getDb();
2112  $rs = $oDb->execute("update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $dAmount where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
2113  } elseif ($this->oxarticles__oxparentid->value) {
2114  // article is variant - should be updated this article parent amount
2115  $oUpdateArticle = $this->getParentArticle();
2116  if ($oUpdateArticle) {
2117  $oUpdateArticle->updateSoldAmount($dAmount);
2118  }
2119  }
2120 
2121  return $rs;
2122  }
2123 
2129  public function disableReminder()
2130  {
2131  $oDb = oxDb::getDb();
2132 
2133  return $oDb->execute("update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
2134  }
2135 
2141  public function save()
2142  {
2143  $this->_assignParentDependFields();
2144 
2145  if (($blRet = parent::save())) {
2146  // saving long description
2147  $this->_saveArtLongDesc();
2148  }
2149 
2150  return $blRet;
2151  }
2152 
2156  public function resetParent()
2157  {
2158  $sParentId = $this->oxarticles__oxparentid->value;
2159  $this->oxarticles__oxparentid = new oxField('', oxField::T_RAW);
2160  $this->_blAllowEmptyParentId = true;
2161  $this->save();
2162  $this->_blAllowEmptyParentId = false;
2163 
2164  if ($sParentId !== '') {
2165  $this->onChange(ACTION_UPDATE, null, $sParentId);
2166  }
2167  }
2168 
2169 
2176  public function getPictureGallery()
2177  {
2178  $myConfig = $this->getConfig();
2179 
2180  //initialize
2181  $blMorePic = false;
2182  $aArtPics = array();
2183  $aArtIcons = array();
2184  $iActPicId = 1;
2185  $sActPic = $this->getPictureUrl($iActPicId);
2186 
2187  if (oxRegistry::getConfig()->getRequestParameter('actpicid')) {
2188  $iActPicId = oxRegistry::getConfig()->getRequestParameter('actpicid');
2189  }
2190 
2191  $oStr = getStr();
2192  $iCntr = 0;
2193  $iPicCount = $myConfig->getConfigParam('iPicCount');
2194  $blCheckActivePicId = true;
2195 
2196  for ($i = 1; $i <= $iPicCount; $i++) {
2197  $sPicVal = $this->getPictureUrl($i);
2198  $sIcoVal = $this->getIconUrl($i);
2199  if (!$oStr->strstr($sIcoVal, 'nopic_ico.jpg') && !$oStr->strstr($sIcoVal, 'nopic.jpg') &&
2200  !$oStr->strstr($sPicVal, 'nopic_ico.jpg') && !$oStr->strstr($sPicVal, 'nopic.jpg') &&
2201  $sPicVal !== null
2202  ) {
2203  if ($iCntr) {
2204  $blMorePic = true;
2205  }
2206  $aArtIcons[$i] = $sIcoVal;
2207  $aArtPics[$i] = $sPicVal;
2208  $iCntr++;
2209 
2210  if ($iActPicId == $i) {
2211  $sActPic = $sPicVal;
2212  $blCheckActivePicId = false;
2213  }
2214 
2215  } elseif ($blCheckActivePicId && $iActPicId <= $i) {
2216  // if picture is empty, setting active pic id to next
2217  // picture
2218  $iActPicId++;
2219  }
2220  }
2221 
2222  $blZoomPic = false;
2223  $aZoomPics = array();
2224  $iZoomPicCount = $myConfig->getConfigParam('iPicCount');
2225 
2226  for ($j = 1, $c = 1; $j <= $iZoomPicCount; $j++) {
2227  $sVal = $this->getZoomPictureUrl($j);
2228 
2229  if ($sVal && !$oStr->strstr($sVal, 'nopic.jpg')) {
2230  $blZoomPic = true;
2231  $aZoomPics[$c]['id'] = $c;
2232  $aZoomPics[$c]['file'] = $sVal;
2233  //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
2234  if (!$sVal) {
2235  $aZoomPics[$c]['file'] = "nopic.jpg";
2236  }
2237  $c++;
2238  }
2239  }
2240 
2241  $aPicGallery = array('ActPicID' => $iActPicId,
2242  'ActPic' => $sActPic,
2243  'MorePics' => $blMorePic,
2244  'Pics' => $aArtPics,
2245  'Icons' => $aArtIcons,
2246  'ZoomPic' => $blZoomPic,
2247  'ZoomPics' => $aZoomPics);
2248 
2249  return $aPicGallery;
2250  }
2251 
2265  public function onChange($sAction = null, $sOXID = null, $sParentID = null)
2266  {
2267  $myConfig = $this->getConfig();
2268 
2269  if (!isset($sOXID)) {
2270  if ($this->getId()) {
2271  $sOXID = $this->getId();
2272  }
2273  if (!isset ($sOXID)) {
2274  $sOXID = $this->oxarticles__oxid->value;
2275  }
2276  if ($this->oxarticles__oxparentid->value) {
2277  $sParentID = $this->oxarticles__oxparentid->value;
2278  }
2279  }
2280  if (!isset($sOXID)) {
2281  return;
2282  }
2283 
2284  //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
2285  if ($myConfig->getConfigParam('blUseStock')) {
2286  //if article has variants then updating oxvarstock field
2287  //getting parent id
2288  if (!isset($sParentID)) {
2289  $oDb = oxDb::getDb();
2290  $sQ = 'select oxparentid from oxarticles where oxid = ' . $oDb->quote($sOXID);
2291  $sParentID = $oDb->getOne($sQ);
2292  }
2293  //if we have parent id then update stock
2294  if ($sParentID) {
2295  $this->_onChangeUpdateStock($sParentID);
2296  }
2297  }
2298  //if we have parent id then update count
2299  //update count even if blUseStock is not active
2300  if ($sParentID) {
2301  $this->_onChangeUpdateVarCount($sParentID);
2302  }
2303 
2304  $sId = ($sParentID) ? $sParentID : $sOXID;
2305  $this->_setVarMinMaxPrice($sId);
2306 
2307  $this->_updateParentDependFields();
2308 
2309  // resetting articles count cache if stock has changed and some
2310  // articles goes offline (M:1448)
2311  if ($sAction === ACTION_UPDATE_STOCK) {
2312  $this->_assignStock();
2313  $this->_onChangeStockResetCount($sOXID);
2314  }
2315 
2316  }
2317 
2324  public function getCustomVAT()
2325  {
2326  if (isset($this->oxarticles__oxvat->value)) {
2327  return $this->oxarticles__oxvat->value;
2328  }
2329  }
2330 
2340  public function checkForStock($dAmount, $dArtStockAmount = 0, $selectForUpdate = false)
2341  {
2342  $myConfig = $this->getConfig();
2343  if (!$myConfig->getConfigParam('blUseStock')) {
2344  return true;
2345  }
2346 
2348  // fetching DB info as its up-to-date
2349  $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = ' . $oDb->quote($this->getId());
2350  $sQ .= $selectForUpdate ? ' FOR UPDATE ' : '';
2351  $rs = $oDb->select($sQ);
2352 
2353  $iOnStock = 0;
2354  $iStockFlag = 0;
2355  if ($rs !== false && $rs->recordCount() > 0) {
2356  $iOnStock = $rs->fields['oxstock'] - $dArtStockAmount;
2357  $iStockFlag = $rs->fields['oxstockflag'];
2358 
2359  //When using stockflag 1 and 4 with basket reservations enabled but disallowing
2360  //negative stock values we would allow to reserve more items than are initially available
2361  //by keeping the stock level not lower than zero. When discarding reservations
2362  //stock level might differ from original value.
2363  if (!$myConfig->getConfigParam('blPsBasketReservationEnabled')
2364  || ($myConfig->getConfigParam('blPsBasketReservationEnabled')
2365  && $myConfig->getConfigParam('blAllowNegativeStock'))
2366  ) {
2367  // foreign stock is also always considered as on stock
2368  if ($iStockFlag == 1 || $iStockFlag == 4) {
2369  return true;
2370  }
2371  }
2372  if (!$myConfig->getConfigParam('blAllowUnevenAmounts')) {
2373  $iOnStock = floor($iOnStock);
2374  }
2375  }
2376  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
2377  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
2378  }
2379  if ($iOnStock >= $dAmount) {
2380  return true;
2381  } else {
2382  if ($iOnStock > 0) {
2383  return $iOnStock;
2384  } else {
2385  $oEx = oxNew('oxArticleInputException');
2386  $oEx->setMessage('ERROR_MESSAGE_ARTICLE_ARTICLE_NOT_BUYABLE');
2387  oxRegistry::get("oxUtilsView")->addErrorToDisplay($oEx);
2388 
2389  return false;
2390  }
2391  }
2392  }
2393 
2394 
2400  public function getLongDescription()
2401  {
2402  if ($this->_oLongDesc === null) {
2403  // initializing
2404  $this->_oLongDesc = new oxField();
2405 
2406 
2407  // choosing which to get..
2408  $sOxid = $this->getId();
2409  $sViewName = getViewName('oxartextends', $this->getLanguage());
2410 
2411  $oDb = oxDb::getDb();
2412  $sDbValue = $oDb->getOne("select oxlongdesc from {$sViewName} where oxid = " . $oDb->quote($sOxid));
2413 
2414  if ($sDbValue != false) {
2415  $this->_oLongDesc->setValue($sDbValue, oxField::T_RAW);
2416  } elseif ($this->oxarticles__oxparentid->value) {
2417  if (!$this->isAdmin() || $this->_blLoadParentData) {
2418  $oParent = $this->getParentArticle();
2419  if ($oParent) {
2420  $this->_oLongDesc->setValue($oParent->getLongDescription()->getRawValue(), oxField::T_RAW);
2421  }
2422  }
2423  }
2424  }
2425 
2426  return $this->_oLongDesc;
2427  }
2428 
2435  public function getLongDesc()
2436  {
2437  return oxRegistry::get("oxUtilsView")->parseThroughSmarty($this->getLongDescription()->getRawValue(), $this->getId() . $this->getLanguage(), null, true);
2438  }
2439 
2447  public function setArticleLongDesc($sDesc)
2448  {
2449 
2450  // setting current value
2451  $this->_oLongDesc = new oxField($sDesc, oxField::T_RAW);
2452  $this->oxarticles__oxlongdesc = new oxField($sDesc, oxField::T_RAW);
2453  }
2454 
2460  public function getAttributes()
2461  {
2462  if ($this->_oAttributeList === null) {
2463  $this->_oAttributeList = oxNew('oxattributelist');
2464  $this->_oAttributeList->loadAttributes($this->getId(), $this->getParentId());
2465  }
2466 
2467  return $this->_oAttributeList;
2468  }
2469 
2476  {
2477  if ($this->_oAttributeList === null) {
2478  $this->_oAttributeList = oxNew('oxattributelist');
2479  $this->_oAttributeList->loadAttributesDisplayableInBasket($this->getId(), $this->getParentId());
2480  }
2481 
2482  return $this->_oAttributeList;
2483  }
2484 
2485 
2492  public function appendLink($sAddParams, $iLang = null)
2493  {
2494  if ($sAddParams) {
2495  if ($iLang === null) {
2496  $iLang = $this->getLanguage();
2497  }
2498 
2499  $this->_aSeoAddParams[$iLang] = isset($this->_aSeoAddParams[$iLang]) ? $this->_aSeoAddParams[$iLang] . "&amp;" : "";
2500  $this->_aSeoAddParams[$iLang] .= $sAddParams;
2501  }
2502  }
2503 
2512  public function getBaseSeoLink($iLang, $blMain = false)
2513  {
2515  $oEncoder = oxRegistry::get("oxSeoEncoderArticle");
2516  if (!$blMain) {
2517  return $oEncoder->getArticleUrl($this, $iLang, $this->getLinkType());
2518  }
2519 
2520  return $oEncoder->getArticleMainUrl($this, $iLang);
2521  }
2522 
2531  public function getLink($iLang = null, $blMain = false)
2532  {
2533  if (!oxRegistry::getUtils()->seoIsActive()) {
2534  return $this->getStdLink($iLang);
2535  }
2536 
2537  if ($iLang === null) {
2538  $iLang = $this->getLanguage();
2539  }
2540 
2541  $iLinkType = $this->getLinkType();
2542  if (!isset($this->_aSeoUrls[$iLang][$iLinkType])) {
2543  $this->_aSeoUrls[$iLang][$iLinkType] = $this->getBaseSeoLink($iLang, $blMain);
2544  }
2545 
2546  $sUrl = $this->_aSeoUrls[$iLang][$iLinkType];
2547  if (isset($this->_aSeoAddParams[$iLang])) {
2548  $sUrl .= ((strpos($sUrl . $this->_aSeoAddParams[$iLang], '?') === false) ? '?' : '&amp;') . $this->_aSeoAddParams[$iLang];
2549  }
2550 
2551  return $sUrl;
2552  }
2553 
2562  public function getMainLink($iLang = null)
2563  {
2564  return $this->getLink($iLang, true);
2565  }
2566 
2572  public function setLinkType($iType)
2573  {
2574  // resetting details link, to force new
2575  $this->_sDetailLink = null;
2576 
2577  // setting link type
2578  $this->_iLinkType = (int) $iType;
2579  }
2580 
2586  public function getLinkType()
2587  {
2588  return $this->_iLinkType;
2589  }
2590 
2597  public function appendStdLink($sAddParams, $iLang = null)
2598  {
2599  if ($sAddParams) {
2600  if ($iLang === null) {
2601  $iLang = $this->getLanguage();
2602  }
2603 
2604  $this->_aStdAddParams[$iLang] = isset($this->_aStdAddParams[$iLang]) ? $this->_aStdAddParams[$iLang] . "&amp;" : "";
2605  $this->_aStdAddParams[$iLang] .= $sAddParams;
2606  }
2607  }
2608 
2618  public function getBaseStdLink($iLang, $blAddId = true, $blFull = true)
2619  {
2620  $sUrl = '';
2621  if ($blFull) {
2622  //always returns shop url, not admin
2623  $sUrl = $this->getConfig()->getShopUrl($iLang, false);
2624  }
2625 
2626  $sUrl .= "index.php?cl=details" . ($blAddId ? "&amp;anid=" . $this->getId() : "");
2627 
2628  return $sUrl . (isset($this->_aStdAddParams[$iLang]) ? "&amp;" . $this->_aStdAddParams[$iLang] : "");
2629  }
2630 
2639  public function getStdLink($iLang = null, $aParams = array())
2640  {
2641  if ($iLang === null) {
2642  $iLang = $this->getLanguage();
2643  }
2644 
2645  if (!isset($this->_aStdUrls[$iLang])) {
2646  $this->_aStdUrls[$iLang] = $this->getBaseStdLink($iLang);
2647  }
2648 
2649  return oxRegistry::get("oxUtilsUrl")->processUrl($this->_aStdUrls[$iLang], true, $aParams, $iLang);
2650  }
2651 
2657  public function getMediaUrls()
2658  {
2659  if ($this->_aMediaUrls === null) {
2660  $this->_aMediaUrls = oxNew("oxlist");
2661  $this->_aMediaUrls->init("oxmediaurl");
2662  $this->_aMediaUrls->getBaseObject()->setLanguage($this->getLanguage());
2663 
2664  $sViewName = getViewName("oxmediaurls", $this->getLanguage());
2665  $sQ = "select * from {$sViewName} where oxobjectid = '" . $this->getId() . "'";
2666  $this->_aMediaUrls->selectString($sQ);
2667  }
2668 
2669  return $this->_aMediaUrls;
2670  }
2671 
2677  public function getDynImageDir()
2678  {
2679  return $this->_sDynImageDir;
2680  }
2681 
2687  public function getDispSelList()
2688  {
2689  if ($this->_aDispSelList === null) {
2690  if ($this->getConfig()->getConfigParam('bl_perfLoadSelectLists') && $this->getConfig()->getConfigParam('bl_perfLoadSelectListsInAList')) {
2691  $this->_aDispSelList = $this->getSelectLists();
2692  }
2693  }
2694 
2695  return $this->_aDispSelList;
2696  }
2697 
2703  public function getMoreDetailLink()
2704  {
2705  if ($this->_sMoreDetailLink == null) {
2706 
2707  // and assign special article values
2708  $this->_sMoreDetailLink = $this->getConfig()->getShopHomeURL() . 'cl=moredetails';
2709 
2710  // not always it is okey, as not all the time active category is the same as primary article cat.
2711  if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
2712  $this->_sMoreDetailLink .= '&amp;cnid=' . $sActCat;
2713  }
2714  $this->_sMoreDetailLink .= '&amp;anid=' . $this->getId();
2715  $this->_sMoreDetailLink = $this->_sMoreDetailLink;
2716  }
2717 
2718  return $this->_sMoreDetailLink;
2719  }
2720 
2726  public function getToBasketLink()
2727  {
2728  if ($this->_sToBasketLink == null) {
2729  $myConfig = $this->getConfig();
2730 
2731  if (oxRegistry::getUtils()->isSearchEngine()) {
2732  $this->_sToBasketLink = $this->getLink();
2733  } else {
2734  // and assign special article values
2735  $this->_sToBasketLink = $myConfig->getShopHomeURL();
2736 
2737  // override some classes as these should never showup
2738  $sActClass = oxRegistry::getConfig()->getRequestParameter('cl');
2739  if ($sActClass == 'thankyou') {
2740  $sActClass = 'basket';
2741  }
2742  $this->_sToBasketLink .= 'cl=' . $sActClass;
2743 
2744  // this is not very correct
2745  if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
2746  $this->_sToBasketLink .= '&amp;cnid=' . $sActCat;
2747  }
2748 
2749  $this->_sToBasketLink .= '&amp;fnc=tobasket&amp;aid=' . $this->getId() . '&amp;anid=' . $this->getId();
2750 
2751  if ($sTpl = basename(oxRegistry::getConfig()->getRequestParameter('tpl'))) {
2752  $this->_sToBasketLink .= '&amp;tpl=' . $sTpl;
2753  }
2754  }
2755  }
2756 
2757  return $this->_sToBasketLink;
2758  }
2759 
2765  public function getStockStatus()
2766  {
2767  return $this->_iStockStatus;
2768  }
2769 
2775  public function getDeliveryDate()
2776  {
2777  if ($this->oxarticles__oxdelivery->value != '0000-00-00') {
2778  return oxRegistry::get("oxUtilsDate")->formatDBDate($this->oxarticles__oxdelivery->value);
2779  }
2780 
2781  return false;
2782  }
2783 
2791  public function getFTPrice()
2792  {
2793  // module
2794  if ($oPrice = $this->getTPrice()) {
2795  if ($dPrice = $this->_getPriceForView($oPrice)) {
2796  return oxRegistry::getLang()->formatCurrency($dPrice);
2797  }
2798  }
2799  }
2800 
2808  public function getFPrice()
2809  {
2810  if ($oPrice = $this->getPrice()) {
2811  $dPrice = $this->_getPriceForView($oPrice);
2812 
2813  return oxRegistry::getLang()->formatCurrency($dPrice);
2814  }
2815  }
2816 
2821  public function resetRemindStatus()
2822  {
2823  if ($this->oxarticles__oxremindactive->value == 2 &&
2824  $this->oxarticles__oxremindamount->value <= $this->oxarticles__oxstock->value
2825  ) {
2826  $this->oxarticles__oxremindactive->value = 1;
2827  }
2828  }
2829 
2837  public function getFNetPrice()
2838  {
2839  if ($oPrice = $this->getPrice()) {
2840  return oxRegistry::getLang()->formatCurrency($oPrice->getNettoPrice());
2841  }
2842  }
2843 
2849  public function isParentNotBuyable()
2850  {
2852  }
2853 
2859  public function isNotBuyable()
2860  {
2861  return $this->_blNotBuyable;
2862  }
2863 
2869  public function setBuyableState($blBuyable = false)
2870  {
2871  $this->_blNotBuyable = !$blBuyable;
2872  }
2873 
2879  public function setSelectlist($aSelList)
2880  {
2881  $this->_aDispSelList = $aSelList;
2882  }
2883 
2891  public function getPictureUrl($iIndex = 1)
2892  {
2893  if ($iIndex) {
2894  $sImgName = false;
2895  if (!$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
2896  $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
2897  }
2898 
2899  $sSize = $this->getConfig()->getConfigParam('aDetailImageSizes');
2900 
2901  return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
2902  }
2903  }
2904 
2913  public function getIconUrl($iIndex = 0)
2914  {
2915  $sImgName = false;
2916  $sDirname = "product/1/";
2917  if ($iIndex && !$this->_isFieldEmpty("oxarticles__oxpic{$iIndex}")) {
2918  $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
2919  $sDirname = "product/{$iIndex}/";
2920  } elseif (!$this->_isFieldEmpty("oxarticles__oxicon")) {
2921  $sImgName = basename($this->oxarticles__oxicon->value);
2922  $sDirname = "product/icon/";
2923  } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
2924  $sImgName = basename($this->oxarticles__oxpic1->value);
2925  }
2926 
2927  $sSize = $this->getConfig()->getConfigParam('sIconsize');
2928 
2929  $sIconUrl = oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, $iIndex);
2930 
2931  return $sIconUrl;
2932  }
2933 
2941  public function getThumbnailUrl($bSsl = null)
2942  {
2943  $sImgName = false;
2944  $sDirname = "product/1/";
2945  if (!$this->_isFieldEmpty("oxarticles__oxthumb")) {
2946  $sImgName = basename($this->oxarticles__oxthumb->value);
2947  $sDirname = "product/thumb/";
2948  } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
2949  $sImgName = basename($this->oxarticles__oxpic1->value);
2950  }
2951 
2952  $sSize = $this->getConfig()->getConfigParam('sThumbnailsize');
2953 
2954  return oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, 0, $bSsl);
2955  }
2956 
2964  public function getZoomPictureUrl($iIndex = '')
2965  {
2966  $iIndex = (int) $iIndex;
2967  if ($iIndex > 0 && !$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
2968  $sImgName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
2969  $sSize = $this->getConfig()->getConfigParam("sZoomImageSize");
2970 
2971  return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
2972  }
2973  }
2974 
2980  public function applyVats(oxPrice $oPrice)
2981  {
2982  $this->_applyVAT($oPrice, $this->getArticleVat());
2983  }
2984 
2990  public function applyDiscountsForVariant($oPrice)
2991  {
2992  // apply discounts
2993  if (!$this->skipDiscounts()) {
2994  $oDiscountList = oxRegistry::get("oxDiscountList");
2995  $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
2996 
2997  reset($aDiscounts);
2998  foreach ($aDiscounts as $oDiscount) {
2999  $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
3000  }
3001  $oPrice->calculateDiscount();
3002  }
3003  }
3004 
3010  public function getParentArticle()
3011  {
3012  if (($sParentId = $this->oxarticles__oxparentid->value)) {
3013  $sIndex = $sParentId . "_" . $this->getLanguage();
3014  if (!isset(self::$_aLoadedParents[$sIndex])) {
3015  self::$_aLoadedParents[$sIndex] = oxNew('oxarticle');
3016  self::$_aLoadedParents[$sIndex]->_blLoadPrice = false;
3017  self::$_aLoadedParents[$sIndex]->_blLoadVariants = false;
3018 
3019  if (!self::$_aLoadedParents[$sIndex]->loadInLang($this->getLanguage(), $sParentId)) {
3020  //return false in case parent product failed to load
3021  self::$_aLoadedParents[$sIndex] = false;
3022  }
3023  }
3024 
3025  return self::$_aLoadedParents[$sIndex];
3026  }
3027  }
3028 
3032  public function updateVariantsRemind()
3033  {
3034  // check if it is parent article
3035  if (!$this->isVariant() && $this->_hasAnyVariant()) {
3036  $oDb = oxDb::getDb();
3037  $sOxId = $oDb->quote($this->getId());
3038  $sOxShopId = $oDb->quote($this->getShopId());
3039  $iRemindActive = $oDb->quote($this->oxarticles__oxremindactive->value);
3040  $sUpdate = "
3041  update oxarticles
3042  set oxremindactive = $iRemindActive
3043  where oxparentid = $sOxId and
3044  oxshopid = $sOxShopId
3045  ";
3046  $oDb->execute($sUpdate);
3047  }
3048  }
3049 
3056  public function getProductId()
3057  {
3058  return $this->getId();
3059  }
3060 
3066  public function getParentId()
3067  {
3068  return $this->oxarticles__oxparentid->value;
3069  }
3070 
3076  public function isOrderArticle()
3077  {
3078  return false;
3079  }
3080 
3086  public function isVariant()
3087  {
3088  return (bool) (isset($this->oxarticles__oxparentid) ? $this->oxarticles__oxparentid->value : false);
3089  }
3090 
3096  public function isMdVariant()
3097  {
3098  $oMdVariant = oxNew("oxVariantHandler");
3099 
3100  return $oMdVariant->isMdVariant($this);
3101  }
3102 
3110  public function getSqlForPriceCategories($sFields = '')
3111  {
3112  if (!$sFields) {
3113  $sFields = 'oxid';
3114  }
3115  $sSelectWhere = "select $sFields from " . $this->_getObjectViewName('oxcategories') . " where";
3116  $sQuotedPrice = oxDb::getDb()->quote($this->oxarticles__oxprice->value);
3117 
3118  return "$sSelectWhere oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice"
3119  . " union $sSelectWhere oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice"
3120  . " union $sSelectWhere oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice";
3121  }
3122 
3130  public function inPriceCategory($sCatNid)
3131  {
3132  $oDb = oxDb::getDb();
3133 
3134  $sQuotedPrice = $oDb->quote($this->oxarticles__oxprice->value);
3135  $sQuotedCnid = $oDb->quote($sCatNid);
3136 
3137  return (bool) $oDb->getOne(
3138  "select 1 from " . $this->_getObjectViewName('oxcategories') . " where oxid=$sQuotedCnid and"
3139  . "( (oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice)"
3140  . " or (oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice)"
3141  . " or (oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice)"
3142  . ")"
3143  );
3144  }
3145 
3151  public function getMdVariants()
3152  {
3153  if ($this->_oMdVariants) {
3154  return $this->_oMdVariants;
3155  }
3156 
3157  $oParentArticle = $this->getParentArticle();
3158  if ($oParentArticle) {
3159  $oVariants = $oParentArticle->getVariants();
3160  } else {
3161  $oVariants = $this->getVariants();
3162  }
3163 
3164  $oVariantHandler = oxNew("oxVariantHandler");
3165  $this->_oMdVariants = $oVariantHandler->buildMdVariants($oVariants, $this->getId());
3166 
3167  return $this->_oMdVariants;
3168  }
3169 
3175  public function getMdSubvariants()
3176  {
3177  return $this->getMdVariants()->getMdSubvariants();
3178  }
3179 
3188  public function getPictureFieldValue($sFieldName, $iIndex = null)
3189  {
3190  if ($sFieldName) {
3191  $sFieldName = "oxarticles__" . $sFieldName . $iIndex;
3192 
3193  return $this->$sFieldName->value;
3194  }
3195  }
3196 
3204  public function getMasterZoomPictureUrl($iIndex)
3205  {
3206  $sPicUrl = false;
3207  $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
3208 
3209  if ($sPicName && $sPicName != "nopic.jpg") {
3210  $sPicUrl = $this->getConfig()->getPictureUrl("master/product/" . $iIndex . "/" . $sPicName);
3211  if (!$sPicUrl || basename($sPicUrl) == "nopic.jpg") {
3212  $sPicUrl = false;
3213  }
3214  }
3215 
3216  return $sPicUrl;
3217  }
3218 
3224  public function getUnitName()
3225  {
3226  if ($this->oxarticles__oxunitname->value) {
3227  return oxRegistry::getLang()->translateString($this->oxarticles__oxunitname->value);
3228  }
3229  }
3230 
3238  public function getArticleFiles($blAddFromParent = false)
3239  {
3240  if ($this->_aArticleFiles === null) {
3241 
3242  $this->_aArticleFiles = false;
3243 
3244  $sQ = "SELECT * FROM `oxfiles` WHERE `oxartid` = '" . $this->getId() . "'";
3245 
3246  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && $blAddFromParent) {
3247  $sQ .= " OR `oxartId` = '" . $this->oxarticles__oxparentid->value . "'";
3248  }
3249 
3250  $oArticleFiles = oxNew("oxlist");
3251  $oArticleFiles->init("oxfile");
3252  $oArticleFiles->selectString($sQ);
3253  $this->_aArticleFiles = $oArticleFiles;
3254 
3255  }
3256 
3257  return $this->_aArticleFiles;
3258  }
3259 
3265  public function isDownloadable()
3266  {
3267  return $this->oxarticles__oxisdownloadable->value;
3268  }
3269 
3275  public function hasAmountPrice()
3276  {
3277  if (self::$_blHasAmountPrice === null) {
3278 
3279  self::$_blHasAmountPrice = false;
3280 
3281  $oDb = oxDb::getDb();
3282  $sQ = "SELECT 1 FROM `oxprice2article` LIMIT 1";
3283 
3284  if ($oDb->getOne($sQ)) {
3285  self::$_blHasAmountPrice = true;
3286  }
3287  }
3288 
3289  return self::$_blHasAmountPrice;
3290  }
3291 
3301  protected function _loadVariantList($blSimple, $blRemoveNotOrderables = true, $blForceCoreTable = null)
3302  {
3303  $oVariants = array();
3304  if (($sId = $this->getId())) {
3305  //do not load me as a parent later
3306  self::$_aLoadedParents[$sId . "_" . $this->getLanguage()] = $this;
3307 
3308  $myConfig = $this->getConfig();
3309 
3310  if (!$this->_blLoadVariants ||
3311  (!$this->isAdmin() && !$myConfig->getConfigParam('blLoadVariants')) ||
3312  (!$this->isAdmin() && !$this->oxarticles__oxvarcount->value)
3313  ) {
3314  return $oVariants;
3315  }
3316 
3317  // cache
3318  $sCacheKey = $blSimple ? "simple" : "full";
3319  if ($blRemoveNotOrderables) {
3320  if (isset($this->_aVariants[$sCacheKey])) {
3321  return $this->_aVariants[$sCacheKey];
3322  } else {
3323  $this->_aVariants[$sCacheKey] = & $oVariants;
3324  }
3325  } elseif (!$blRemoveNotOrderables) {
3326  if (isset($this->_aVariantsWithNotOrderables[$sCacheKey])) {
3327  return $this->_aVariantsWithNotOrderables[$sCacheKey];
3328  } else {
3329  $this->_aVariantsWithNotOrderables[$sCacheKey] = & $oVariants;
3330  }
3331  }
3332 
3333  if (($this->_blHasVariants = $this->_hasAnyVariant($blForceCoreTable))) {
3334 
3335  //load simple variants for lists
3336  if ($blSimple) {
3337  $oVariants = oxNew('oxsimplevariantlist');
3338  $oVariants->setParent($this);
3339  } else {
3340  //loading variants
3341  $oVariants = oxNew('oxarticlelist');
3342  $oVariants->getBaseObject()->modifyCacheKey('_variants');
3343  }
3344 
3345  startProfile("selectVariants");
3346  $blUseCoreTable = (bool) $blForceCoreTable;
3347  $oBaseObject = $oVariants->getBaseObject();
3348  $oBaseObject->setLanguage($this->getLanguage());
3349 
3350 
3351  $sArticleTable = $this->getViewName($blUseCoreTable);
3352 
3353  $sSelect = "select " . $oBaseObject->getSelectFields($blUseCoreTable) . " from $sArticleTable where " .
3354  $this->getActiveCheckQuery($blUseCoreTable) .
3355  $this->getVariantsQuery($blRemoveNotOrderables, $blUseCoreTable) .
3356  " order by $sArticleTable.oxsort";
3357  $oVariants->selectString($sSelect);
3358 
3359  //if this is multidimensional variants, make additional processing
3360  if ($myConfig->getConfigParam('blUseMultidimensionVariants')) {
3361  $oMdVariants = oxNew("oxVariantHandler");
3362  $this->_blHasMdVariants = $oMdVariants->isMdVariant($oVariants->current());
3363  }
3364  stopProfile("selectVariants");
3365  }
3366 
3367  //if we have variants then depending on config option the parent may be non buyable
3368  if (!$myConfig->getConfigParam('blVariantParentBuyable') && $this->_blHasVariants) {
3369  $this->_blNotBuyableParent = true;
3370  }
3371 
3372  //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
3373  if (!$myConfig->getConfigParam('blVariantParentBuyable') && count($oVariants) == 0 && $this->_blHasVariants) {
3374  $this->_blNotBuyable = true;
3375  }
3376  }
3377 
3378  return $oVariants;
3379  }
3380 
3389  protected function _selectCategoryIds($sSql, $sField)
3390  {
3392  $aResult = $oDb->getAll($sSql);
3393  $aReturn = array();
3394 
3395 
3396  foreach ($aResult as $aValue) {
3397  $aValue = array_change_key_case($aValue, CASE_LOWER);
3398 
3399 
3400  $aReturn[] = $aValue[$sField];
3401  }
3402 
3403  return $aReturn;
3404  }
3405 
3413  protected function _getCategoryIdsSelect($blActCats = false)
3414  {
3415  $sO2CView = $this->_getObjectViewName('oxobject2category');
3416  $sCatView = $this->_getObjectViewName('oxcategories');
3417 
3418  $sArticleIdSql = 'oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getId());
3419  if ($this->getParentId()) {
3420  $sArticleIdSql = '(' . $sArticleIdSql . ' or oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getParentId()) . ')';
3421  }
3422  $sActiveCategorySql = $blActCats ? $this->_getActiveCategorySelectSnippet() : '';
3423 
3424  $sSelect = "select
3425  oxobject2category.oxcatnid as oxcatnid
3426  from $sO2CView as oxobject2category
3427  left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid
3428  where $sArticleIdSql and oxcategories.oxid is not null and oxcategories.oxactive = 1 $sActiveCategorySql
3429  order by oxobject2category.oxtime";
3430 
3431  return $sSelect;
3432  }
3433 
3439  protected function _getActiveCategorySelectSnippet()
3440  {
3441  $sCatView = $this->_getObjectViewName('oxcategories');
3442  $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 ";
3443 
3444  return $sActiveCategorySql;
3445  }
3446 
3457  protected function _getSelectCatIds($sOXID, $blActCats = false)
3458  {
3459  $sO2CView = $this->_getObjectViewName('oxobject2category');
3460  $sCatView = $this->_getObjectViewName('oxcategories');
3461  $sSelect = "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
3462  $sSelect .= 'where oxobject2category.oxobjectid=' . oxDb::getDb()->quote($sOXID) . ' and oxcategories.oxid is not null and oxcategories.oxactive = 1 ';
3463  if ($blActCats) {
3464  $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 ";
3465  }
3466  $sSelect .= 'order by oxobject2category.oxtime ';
3467 
3468  return $sSelect;
3469  }
3470 
3479  protected function _calculatePrice($oPrice, $dVat = null)
3480  {
3481  // apply VAT only if configuration requires it
3482  if (isset($dVat) || !$this->getConfig()->getConfigParam('bl_perfCalcVatOnlyForBasketOrder')) {
3483  $this->_applyVAT($oPrice, isset($dVat) ? $dVat : $this->getArticleVat());
3484  }
3485 
3486  // apply currency
3487  $this->_applyCurrency($oPrice);
3488  // apply discounts
3489  if (!$this->skipDiscounts()) {
3490  $oDiscountList = oxRegistry::get("oxDiscountList");
3491  $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
3492 
3493  reset($aDiscounts);
3494  foreach ($aDiscounts as $oDiscount) {
3495  $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
3496  }
3497  $oPrice->calculateDiscount();
3498  }
3499 
3500  return $oPrice;
3501  }
3502 
3510  protected function _hasAnyVariant($blForceCoreTable = null)
3511  {
3512  $blHas = false;
3513  if (($sId = $this->getId())) {
3514  if ($this->oxarticles__oxshopid->value == $this->getConfig()->getShopId()) {
3515  $blHas = (bool) $this->oxarticles__oxvarcount->value;
3516  } else {
3517  $sArticleTable = $this->getViewName($blForceCoreTable);
3518  $blHas = (bool) oxDb::getDb()->getOne("select 1 from $sArticleTable where oxparentid='{$sId}'");
3519  }
3520  }
3521 
3522  return $blHas;
3523  }
3524 
3530  protected function _isStockStatusChanged()
3531  {
3532  return $this->_iStockStatus != $this->_iStockStatusOnLoad;
3533  }
3534 
3540  protected function _isVisibilityChanged()
3541  {
3542  return $this->_isStockStatusChanged() && ($this->_iStockStatus == -1 || $this->_iStockStatusOnLoad == -1);
3543  }
3544 
3550  protected function _saveArtLongDesc()
3551  {
3552  $myConfig = $this->getConfig();
3553  $sShopId = $myConfig->getShopID();
3554  if (in_array("oxlongdesc", $this->_aSkipSaveFields)) {
3555  return;
3556  }
3557 
3558  if ($this->_blEmployMultilanguage) {
3559  $sValue = $this->getLongDescription()->getRawValue();
3560  if ($sValue !== null) {
3561  $oArtExt = oxNew('oxI18n');
3562  $oArtExt->init('oxartextends');
3563  $oArtExt->setLanguage((int) $this->getLanguage());
3564  if (!$oArtExt->load($this->getId())) {
3565  $oArtExt->setId($this->getId());
3566  }
3567  $oArtExt->oxartextends__oxlongdesc = new oxField($sValue, oxField::T_RAW);
3568  $oArtExt->save();
3569  }
3570  } else {
3571  $oArtExt = oxNew('oxI18n');
3572  $oArtExt->setEnableMultilang(false);
3573  $oArtExt->init('oxartextends');
3574  $aObjFields = $oArtExt->_getAllFields(true);
3575  if (!$oArtExt->load($this->getId())) {
3576  $oArtExt->setId($this->getId());
3577  }
3578 
3579  foreach ($aObjFields as $sKey => $sValue) {
3580  if (preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey)) {
3581  $sField = $this->_getFieldLongName($sKey);
3582 
3583  if (isset($this->$sField)) {
3584  $sLongDesc = null;
3585  if ($this->$sField instanceof oxField) {
3586  $sLongDesc = $this->$sField->getRawValue();
3587  } elseif (is_object($this->$sField)) {
3588  $sLongDesc = $this->$sField->value;
3589  }
3590  if (isset($sLongDesc)) {
3591  $sAEField = $oArtExt->_getFieldLongName($sKey);
3592  $oArtExt->$sAEField = new oxField($sLongDesc, oxField::T_RAW);
3593  }
3594  }
3595  }
3596  }
3597  $oArtExt->save();
3598  }
3599  }
3600 
3604  protected function _skipSaveFields()
3605  {
3606  $myConfig = $this->getConfig();
3607 
3608  $this->_aSkipSaveFields = array();
3609 
3610  $this->_aSkipSaveFields[] = 'oxtimestamp';
3611  // $this->_aSkipSaveFields[] = 'oxlongdesc';
3612  $this->_aSkipSaveFields[] = 'oxinsert';
3614 
3615  if (!$this->_blAllowEmptyParentId && (!isset($this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '')) {
3616  $this->_aSkipSaveFields[] = 'oxparentid';
3617  }
3618 
3619  }
3620 
3630  protected function _mergeDiscounts($aDiscounts, $aItemDiscounts)
3631  {
3632  foreach ($aItemDiscounts as $sKey => $oDiscount) {
3633  // add prices of the same discounts
3634  if (array_key_exists($sKey, $aDiscounts)) {
3635  $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
3636  } else {
3637  $aDiscounts[$sKey] = $oDiscount;
3638  }
3639  }
3640 
3641  return $aDiscounts;
3642  }
3643 
3649  protected function _getGroupPrice()
3650  {
3651  $sPriceSufix = $this->_getUserPriceSufix();
3652  $sVarName = "oxarticles__oxprice{$sPriceSufix}";
3653  $dPrice = $this->$sVarName->value;
3654 
3655  // #1437/1436C - added config option, and check for zero A,B,C price values
3656  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices') && (double) $dPrice == 0) {
3657  $dPrice = $this->oxarticles__oxprice->value;
3658  }
3659 
3660  return $dPrice;
3661  }
3662 
3671  protected function _getAmountPrice($dAmount = 1)
3672  {
3673  startProfile("_getAmountPrice");
3674 
3675  $dPrice = $this->_getGroupPrice();
3676  $oAmtPrices = $this->_getAmountPriceList();
3677  foreach ($oAmtPrices as $oAmPrice) {
3678  if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
3679  && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
3680  && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value
3681  ) {
3682  $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
3683  }
3684  }
3685 
3686  stopProfile("_getAmountPrice");
3687 
3688  return $dPrice;
3689  }
3690 
3699  protected function _modifySelectListPrice($dPrice, $aChosenList = null)
3700  {
3701  $myConfig = $this->getConfig();
3702  // #690
3703  if ($myConfig->getConfigParam('bl_perfLoadSelectLists') && $myConfig->getConfigParam('bl_perfUseSelectlistPrice')) {
3704 
3705  $aSelLists = $this->getSelectLists();
3706 
3707  foreach ($aSelLists as $key => $aSel) {
3708  if (isset($aChosenList[$key]) && isset($aSel[$aChosenList[$key]])) {
3709  $oSel = $aSel[$aChosenList[$key]];
3710  if ($oSel->priceUnit == 'abs') {
3711  $dPrice += $oSel->price;
3712  } elseif ($oSel->priceUnit == '%') {
3713  $dPrice += oxPrice::percent($dPrice, $oSel->price);
3714  }
3715  }
3716  }
3717  }
3718 
3719  return $dPrice;
3720  }
3721 
3729  protected function _fillAmountPriceList($aAmPriceList)
3730  {
3731  $oLang = oxRegistry::getLang();
3732 
3733  // trying to find lowest price value
3734  foreach ($aAmPriceList as $sId => $oItem) {
3735 
3736  $oItemPrice = $this->_getPriceObject();
3737  if ($oItem->oxprice2article__oxaddabs->value) {
3738 
3739  $dBasePrice = $oItem->oxprice2article__oxaddabs->value;
3740  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
3741 
3742  $oItemPrice->setPrice($dBasePrice);
3743  $this->_calculatePrice($oItemPrice);
3744 
3745  } else {
3746  $dBasePrice = $this->_getGroupPrice();
3747  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
3748  $oItemPrice->setPrice($dBasePrice);
3749  $oItemPrice->subtractPercent($oItem->oxprice2article__oxaddperc->value);
3750  }
3751 
3752 
3753  $aAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency($this->_getPriceForView($oItemPrice));
3754  }
3755 
3756  return $aAmPriceList;
3757  }
3758 
3766  public function getVariantIds($blActiveVariants = true)
3767  {
3768  $aSelect = array();
3769  $sId = $this->getId();
3770  if ($sId) {
3771  $sActiveSqlSnippet = "";
3772  if ($blActiveVariants) {
3773  $sActiveSqlSnippet = " and " . $this->getSqlActiveSnippet(true);
3774  }
3776  $sQ = "select oxid from " . $this->getViewName(true) . " where oxparentid = " . $oDb->quote($sId) .
3777  $sActiveSqlSnippet . " order by oxsort";
3778  $oRs = $oDb->select($sQ);
3779  if ($oRs != false && $oRs->recordCount() > 0) {
3780  while (!$oRs->EOF) {
3781  $aSelect[] = reset($oRs->fields);
3782  $oRs->moveNext();
3783  }
3784  }
3785  }
3786 
3787  return $aSelect;
3788  }
3789 
3799  protected function _getVariantsIds($blActiveVariants = true)
3800  {
3801  return $this->getVariantIds($blActiveVariants);
3802  }
3803 
3809  public function getArticleVat()
3810  {
3811  if (!isset($this->_dArticleVat)) {
3812  $this->_dArticleVat = oxRegistry::get("oxVatSelector")->getArticleVat($this);
3813  }
3814 
3815  return $this->_dArticleVat;
3816  }
3817 
3824  protected function _applyVAT(oxPrice $oPrice, $dVat)
3825  {
3826  startProfile(__FUNCTION__);
3827  $oPrice->setVAT($dVat);
3829  $oVatSelector = oxRegistry::get("oxVatSelector");
3830  if (($dVat = $oVatSelector->getArticleUserVat($this)) !== false) {
3831  $oPrice->setUserVat($dVat);
3832  }
3833  stopProfile(__FUNCTION__);
3834  }
3835 
3842  protected function _applyCurrency(oxPrice $oPrice, $oCur = null)
3843  {
3844  if (!$oCur) {
3845  $oCur = $this->getConfig()->getActShopCurrencyObject();
3846  }
3847 
3848  $oPrice->multiply($oCur->rate);
3849  }
3850 
3851 
3858  protected function _getAttribsString(&$sAttributeSql, &$iCnt)
3859  {
3860  // we do not use lists here as we don't need this overhead right now
3861  $oDb = oxDb::getDb();
3862  $sSelect = 'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid=' . $oDb->quote($this->getId());
3863  if ($this->getParentId()) {
3864  $sSelect .= ' OR oxobject2attribute.oxobjectid=' . $oDb->quote($this->getParentId());
3865  }
3866  $sAttributeSql = '';
3867  $aAttributeIds = $oDb->getCol($sSelect);
3868  if (is_array($aAttributeIds) && count($aAttributeIds)) {
3869  $aAttributeIds = array_unique($aAttributeIds);
3870  $iCnt = count($aAttributeIds);
3871  $sAttributeSql .= 't1.oxattrid IN ( ' . implode(',', $oDb->quoteArray($aAttributeIds)) . ') ';
3872  }
3873  }
3874 
3883  protected function _getSimList($sAttributeSql, $iCnt)
3884  {
3885  // #523A
3886  $iAttrPercent = $this->getConfig()->getConfigParam('iAttributesPercent') / 100;
3887  // 70% same attributes
3888  if (!$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
3889  $iAttrPercent = 0.70;
3890  }
3891  // #1137V iAttributesPercent = 100 doesn't work
3892  $iHitMin = ceil($iCnt * $iAttrPercent);
3893 
3894  $aExcludeIds = array();
3895  $aExcludeIds[] = $this->getId();
3896  if ($this->getParentId()) {
3897  $aExcludeIds[] = $this->getParentId();
3898  }
3899 
3900  // we do not use lists here as we don't need this overhead right now
3901  $sSelect = "select oxobjectid from oxobject2attribute as t1 where
3902  ( $sAttributeSql )
3903  and t1.oxobjectid NOT IN (" . implode(', ', oxDb::getDb()->quoteArray($aExcludeIds)) . ")
3904  group by t1.oxobjectid having count(*) >= $iHitMin LIMIT 0, 20";
3905 
3906  return oxDb::getDb()->getCol($sSelect);
3907  }
3908 
3917  protected function _generateSimListSearchStr($sArticleTable, $aList)
3918  {
3919  $sFieldList = $this->getSelectFields();
3920  $aList = array_slice($aList, 0, $this->getConfig()->getConfigParam('iNrofSimilarArticles'));
3921 
3922  $sSearch = "select $sFieldList from $sArticleTable where " . $this->getSqlActiveSnippet() . " and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
3923 
3924  $sSearch .= implode(',', oxdb::getDb()->quoteArray($aList)) . ')';
3925 
3926  // #524A -- randomizing articles in attribute list
3927  $sSearch .= ' order by rand() ';
3928 
3929  return $sSearch;
3930  }
3931 
3940  protected function _generateSearchStr($sOXID, $blSearchPriceCat = false)
3941  {
3942 
3943  $sCatView = getViewName('oxcategories', $this->getLanguage());
3944  $sO2CView = getViewName('oxobject2category');
3945 
3946  // we do not use lists here as we don't need this overhead right now
3947  if (!$blSearchPriceCat) {
3948  $sSelect = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
3949  {$sCatView}.oxid = oxobject2category.oxcatnid
3950  where oxobject2category.oxobjectid=" . oxDb::getDb()->quote($sOXID) . " and {$sCatView}.oxid is not null ";
3951  } else {
3952  $sSelect = "select {$sCatView}.* from {$sCatView} where
3953  '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
3954  '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
3955  }
3956 
3957  return $sSelect;
3958  }
3959 
3966  {
3967  $sArtTable = $this->getViewName();
3968  $sOrderArtTable = getViewName('oxorderarticles');
3969 
3970  // fetching filter params
3971  $sIn = " '{$this->oxarticles__oxid->value}' ";
3972  if ($this->oxarticles__oxparentid->value) {
3973 
3974  // adding article parent
3975  $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
3976  $sParentIdForVariants = $this->oxarticles__oxparentid->value;
3977 
3978  } else {
3979  $sParentIdForVariants = $this->getId();
3980  }
3981 
3982  // adding variants
3984  $oRs = $oDb->select("select oxid from {$sArtTable} where oxparentid = " . $oDb->quote($sParentIdForVariants) . " and oxid != " . $oDb->quote($this->oxarticles__oxid->value));
3985  if ($oRs != false && $oRs->recordCount() > 0) {
3986  while (!$oRs->EOF) {
3987  $sIn .= ", " . $oDb->quote(current($oRs->fields)) . " ";
3988  $oRs->moveNext();
3989  }
3990  }
3991 
3992  $iLimit = (int) $this->getConfig()->getConfigParam('iNrofCustomerWhoArticles');
3993  $iLimit = $iLimit ? ($iLimit * 10) : 50;
3994 
3995  // building sql (optimized)
3996  $sQ = "select distinct {$sArtTable}.* from (
3997  select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
3998  ) as suborder
3999  left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
4000  left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
4001  where {$sArtTable}.oxid not in ( {$sIn} )
4002  and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and " . $this->getSqlActiveSnippet();
4003 
4004  /* non optimized, but could be used if index forcing is not supported
4005  // building sql
4006  $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
4007  select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
4008  ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
4009  and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
4010  and ".$this->getSqlActiveSnippet();
4011  */
4012 
4013  return $sQ;
4014  }
4015 
4025  protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
4026  {
4027  $sCategoryView = getViewName('oxcategories');
4028  $sO2CView = getViewName('oxobject2category');
4029 
4030  $oDb = oxDb::getDb();
4031  $sOXID = $oDb->quote($sOXID);
4032  $sCatId = $oDb->quote($sCatId);
4033 
4034  if (!$dPriceFromTo) {
4035  $sSelect = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
4036  $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
4037  $sSelect .= "where oxobject2category.oxcatnid=$sCatId and oxobject2category.oxobjectid=$sOXID ";
4038  $sSelect .= "and oxcategories.oxactive = 1 order by oxobject2category.oxtime ";
4039  } else {
4040  $dPriceFromTo = $oDb->quote($dPriceFromTo);
4041  $sSelect = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
4042  $sSelect .= "oxcategories.oxid=$sCatId and $dPriceFromTo >= oxcategories.oxpricefrom and ";
4043  $sSelect .= "$dPriceFromTo <= oxcategories.oxpriceto ";
4044  }
4045 
4046  return $sSelect;
4047  }
4048 
4054  protected function _getAmountPriceList()
4055  {
4056  if ($this->_oAmountPriceList === null) {
4057  $oAmPriceList = oxNew('oxAmountPricelist');
4058 
4059  if (!$this->skipDiscounts()) {
4060  //collecting assigned to article amount-price list
4061  $oAmPriceList->load($this);
4062 
4063  // prepare abs prices if currently having percentages
4064  $oBasePrice = $this->_getGroupPrice();
4065  foreach ($oAmPriceList as $oAmPrice) {
4066  if ($oAmPrice->oxprice2article__oxaddperc->value) {
4067  $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent($oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value), oxField::T_RAW);
4068  }
4069  }
4070 
4071  }
4072 
4073  $this->_oAmountPriceList = $oAmPriceList;
4074  }
4075 
4076  return $this->_oAmountPriceList;
4077  }
4078 
4086  protected function _isFieldEmpty($sFieldName)
4087  {
4088  $mValue = $this->$sFieldName->value;
4089 
4090  if (is_null($mValue)) {
4091  return true;
4092  }
4093 
4094  if ($mValue === '') {
4095  return true;
4096  }
4097 
4098  // certain fields with zero value treat as empty
4099  $aZeroValueFields = array('oxarticles__oxprice', 'oxarticles__oxvat', 'oxarticles__oxunitquantity');
4100 
4101  if (!$mValue && in_array($sFieldName, $aZeroValueFields)) {
4102  return true;
4103  }
4104 
4105 
4106  if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
4107  return true;
4108  }
4109 
4110  $sFieldName = strtolower($sFieldName);
4111 
4112  if ($sFieldName == 'oxarticles__oxicon' && (strpos($mValue, "nopic_ico.jpg") !== false || strpos($mValue, "nopic.jpg") !== false)) {
4113  return true;
4114  }
4115 
4116  if (strpos($mValue, "nopic.jpg") !== false && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom')) {
4117  return true;
4118  }
4119 
4120  return false;
4121  }
4122 
4130  protected function _assignParentFieldValue($sFieldName)
4131  {
4132  if (!($oParentArticle = $this->getParentArticle())) {
4133  return;
4134  }
4135 
4136  $sCopyFieldName = $this->_getFieldLongName($sFieldName);
4137 
4138  // assigning only these which parent article has
4139  if ($oParentArticle->$sCopyFieldName != null) {
4140 
4141  // only overwrite database values
4142  if (substr($sCopyFieldName, 0, 12) != 'oxarticles__') {
4143  return;
4144  }
4145 
4146  //do not copy certain fields
4147  if (in_array($sCopyFieldName, $this->_aNonCopyParentFields)) {
4148  return;
4149  }
4150 
4151  //skip picture parent value assignment in case master image is set for variant
4152  if ($this->_isFieldEmpty($sCopyFieldName) && $this->_isImageField($sCopyFieldName) && $this->_hasMasterImage(1)) {
4153  return;
4154  }
4155 
4156  //COPY THE VALUE
4157  if ($this->_isFieldEmpty($sCopyFieldName)) {
4158  $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
4159  }
4160  }
4161  }
4162 
4170  protected function _isImageField($sFieldName)
4171  {
4172  $blIsImageField = (stristr($sFieldName, '_oxthumb') || stristr($sFieldName, '_oxicon') || stristr($sFieldName, '_oxzoom') || stristr($sFieldName, '_oxpic'));
4173 
4174  return $blIsImageField;
4175  }
4176 
4180  protected function _assignParentFieldValues()
4181  {
4182  startProfile('articleAssignParentInternal');
4183  if ($this->oxarticles__oxparentid->value) {
4184  // yes, we are in fact a variant
4185  if (!$this->isAdmin() || ($this->_blLoadParentData && $this->isAdmin())) {
4186  foreach ($this->_aFieldNames as $sFieldName => $sVal) {
4187  $this->_assignParentFieldValue($sFieldName);
4188  }
4189  }
4190  }
4191  stopProfile('articleAssignParentInternal');
4192  }
4193 
4197  protected function _assignNotBuyableParent()
4198  {
4199  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') &&
4200  ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value)
4201  ) {
4202  $this->_blNotBuyableParent = true;
4203 
4204  }
4205  }
4206 
4210  protected function _assignStock()
4211  {
4212  $myConfig = $this->getConfig();
4213  // -----------------------------------
4214  // stock
4215  // -----------------------------------
4216 
4217  // #1125 A. must round (using floor()) value taken from database and cast to int
4218  if (!$myConfig->getConfigParam('blAllowUnevenAmounts') && !$this->isAdmin()) {
4219  $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
4220  }
4221  //GREEN light
4222  $this->_iStockStatus = 0;
4223 
4224  // if we have flag /*1 or*/ 4 - we show always green light
4225  if ($myConfig->getConfigParam('blUseStock') && /*$this->oxarticles__oxstockflag->value != 1 && */
4226  $this->oxarticles__oxstockflag->value != 4
4227  ) {
4228  //ORANGE light
4229  $iStock = $this->oxarticles__oxstock->value;
4230 
4231  if ($this->_blNotBuyableParent) {
4232  $iStock = $this->oxarticles__oxvarstock->value;
4233  }
4234 
4235 
4236  if ($iStock <= $myConfig->getConfigParam('sStockWarningLimit') && $iStock > 0) {
4237  $this->_iStockStatus = 1;
4238  }
4239 
4240  //RED light
4241  if ($iStock <= 0) {
4242  $this->_iStockStatus = -1;
4243  }
4244  }
4245 
4246 
4247  // stock
4248  if ($myConfig->getConfigParam('blUseStock') && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
4249  $iOnStock = $this->oxarticles__oxstock->value;
4250  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
4251  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
4252  }
4253  if ($iOnStock <= 0) {
4254  $this->setBuyableState(false);
4255  }
4256  }
4257 
4258  //exceptional handling for variant parent stock:
4259  if ($this->_blNotBuyable && $this->oxarticles__oxvarstock->value) {
4260  $this->setBuyableState(true);
4261  //but then at least setting notBuaybleParent to true
4262  $this->_blNotBuyableParent = true;
4263  }
4264 
4265  //special treatment for lists when blVariantParentBuyable config option is set to false
4266  //then we just hide "to basket" button.
4267  //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
4268  if (!$myConfig->getConfigParam('blVariantParentBuyable') && !$myConfig->getConfigParam('blLoadVariants') && $this->oxarticles__oxvarstock->value) {
4269  $this->setBuyableState(false);
4270  }
4271 
4272  //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
4273  if (!$this->_blNotBuyable && $this->_blNotBuyableParent && $this->oxarticles__oxvarcount->value == 0) {
4274  $this->setBuyableState(false);
4275  }
4276  }
4277 
4281  protected function _assignPersistentParam()
4282  {
4283  // Persistent Parameter Handling
4284  $aPersParam = oxRegistry::getSession()->getVariable('persparam');
4285  if (isset($aPersParam) && isset($aPersParam[$this->getId()])) {
4286  $this->_aPersistParam = $aPersParam[$this->getId()];
4287  }
4288  }
4289 
4293  protected function _assignDynImageDir()
4294  {
4295  $myConfig = $this->getConfig();
4296 
4297  $sThisShop = $this->oxarticles__oxshopid->value;
4298 
4299  $this->_sDynImageDir = $myConfig->getPictureUrl(null, false);
4300  $this->dabsimagedir = $myConfig->getPictureDir(false); //$sThisShop
4301  $this->nossl_dimagedir = $myConfig->getPictureUrl(null, false, false, null, $sThisShop); //$sThisShop
4302  $this->ssl_dimagedir = $myConfig->getPictureUrl(null, false, true, null, $sThisShop); //$sThisShop
4303  }
4304 
4308  protected function _assignComparisonListFlag()
4309  {
4310  // #657 add a flag if article is on comparisonlist
4311 
4312  $aItems = oxRegistry::getSession()->getVariable('aFiltcompproducts');
4313  if (isset($aItems[$this->getId()])) {
4314  $this->_blIsOnComparisonList = true;
4315  }
4316  }
4317 
4325  protected function _insert()
4326  {
4327  // set oxinsert
4328  $sNow = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
4329  $this->oxarticles__oxinsert = new oxField($sNow);
4330  if (!is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
4331  $this->oxarticles__oxsubclass = new oxField('oxarticle');
4332  }
4333 
4334  $blRes = parent::_insert();
4335 
4336 
4337  return $blRes;
4338  }
4339 
4345  protected function _update()
4346  {
4347 
4348  $this->setUpdateSeo(true);
4349  $this->_setUpdateSeoOnFieldChange('oxtitle');
4350 
4351  $this->_skipSaveFields();
4352 
4353  $myConfig = $this->getConfig();
4354 
4355 
4356  $blRes = parent::_update();
4357 
4358 
4359  return $blRes;
4360  }
4361 
4369  protected function _deleteRecords($sOXID)
4370  {
4371  $oDb = oxDb::getDb();
4372 
4373  $sOXID = $oDb->quote($sOXID);
4374 
4375  //remove other records
4376  $sDelete = 'delete from oxobject2article where oxarticlenid = ' . $sOXID . ' or oxobjectid = ' . $sOXID . ' ';
4377  $oDb->execute($sDelete);
4378 
4379  $sDelete = 'delete from oxobject2attribute where oxobjectid = ' . $sOXID . ' ';
4380  $oDb->execute($sDelete);
4381 
4382  $sDelete = 'delete from oxobject2category where oxobjectid = ' . $sOXID . ' ';
4383  $oDb->execute($sDelete);
4384 
4385  $sDelete = 'delete from oxobject2selectlist where oxobjectid = ' . $sOXID . ' ';
4386  $oDb->execute($sDelete);
4387 
4388  $sDelete = 'delete from oxprice2article where oxartid = ' . $sOXID . ' ';
4389  $oDb->execute($sDelete);
4390 
4391  $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = ' . $sOXID . ' ';
4392  $oDb->execute($sDelete);
4393 
4394  $sDelete = 'delete from oxratings where oxobjectid = ' . $sOXID . ' ';
4395  $rs = $oDb->execute($sDelete);
4396 
4397  $sDelete = 'delete from oxaccessoire2article where oxobjectid = ' . $sOXID . ' or oxarticlenid = ' . $sOXID . ' ';
4398  $oDb->execute($sDelete);
4399 
4400  //#1508C - deleting oxobject2delivery entries added
4401  $sDelete = 'delete from oxobject2delivery where oxobjectid = ' . $sOXID . ' and oxtype=\'oxarticles\' ';
4402  $oDb->execute($sDelete);
4403 
4404  $sDelete = 'delete from oxartextends where oxid = ' . $sOXID . ' ';
4405  $oDb->execute($sDelete);
4406 
4407  //delete the record
4408  foreach ($this->_getLanguageSetTables("oxartextends") as $sSetTbl) {
4409  $oDb->execute("delete from $sSetTbl where oxid = {$sOXID}");
4410  }
4411 
4412  $sDelete = 'delete from oxactions2article where oxartid = ' . $sOXID . ' ';
4413  $rs = $oDb->execute($sDelete);
4414 
4415  $sDelete = 'delete from oxobject2list where oxobjectid = ' . $sOXID . ' ';
4416  $rs = $oDb->execute($sDelete);
4417 
4418 
4419  return $rs;
4420  }
4421 
4427  protected function _deleteVariantRecords($sOXID)
4428  {
4429  if ($sOXID) {
4430  $oDb = oxDb::getDb();
4431  //collect variants to remove recursively
4432  $sQ = 'select oxid from ' . $this->getViewName() . ' where oxparentid = ' . $oDb->quote($sOXID);
4433  $rs = $oDb->select($sQ, false, false);
4434  $oArticle = oxNew("oxArticle");
4435  if ($rs != false && $rs->recordCount() > 0) {
4436  while (!$rs->EOF) {
4437  $oArticle->setId($rs->fields[0]);
4438  $oArticle->delete();
4439  $rs->moveNext();
4440  }
4441  }
4442  }
4443  }
4444 
4448  protected function _deletePics()
4449  {
4450  $myUtilsPic = oxRegistry::get("oxUtilsPic");
4451  $myConfig = $this->getConfig();
4452  $oPictureHandler = oxRegistry::get("oxPictureHandler");
4453 
4454  //deleting custom main icon
4455  $oPictureHandler->deleteMainIcon($this);
4456 
4457  //deleting custom thumbnail
4458  $oPictureHandler->deleteThumbnail($this);
4459 
4460  $sAbsDynImageDir = $myConfig->getPictureDir(false);
4461 
4462  // deleting master image and all generated images
4463  $iPicCount = $myConfig->getConfigParam('iPicCount');
4464  for ($i = 1; $i <= $iPicCount; $i++) {
4465  $oPictureHandler->deleteArticleMasterPicture($this, $i);
4466  }
4467  }
4468 
4476  protected function _onChangeResetCounts($sOxid, $sVendorId = null, $sManufacturerId = null)
4477  {
4478  $myUtilsCount = oxRegistry::get("oxUtilsCount");
4479 
4480  if ($sVendorId) {
4481  $myUtilsCount->resetVendorArticleCount($sVendorId);
4482  }
4483 
4484  if ($sManufacturerId) {
4485  $myUtilsCount->resetManufacturerArticleCount($sManufacturerId);
4486  }
4487 
4488  $aCategoryIds = $this->getCategoryIds();
4489  //also reseting category counts
4490  foreach ($aCategoryIds as $sCatId) {
4491  $myUtilsCount->resetCatArticleCount($sCatId, false);
4492  }
4493  }
4494 
4500  protected function _onChangeUpdateStock($sParentID)
4501  {
4502  if ($sParentID) {
4503  $oDb = oxDb::getDb();
4504  $sParentIdQuoted = $oDb->quote($sParentID);
4505  $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = ' . $sParentIdQuoted;
4506  $rs = $oDb->select($sQ, false, false);
4507  $iOldStock = $rs->fields[0];
4508  $iVendorID = $rs->fields[1];
4509  $iManufacturerID = $rs->fields[2];
4510 
4511  $sQ = 'select sum(oxstock) from ' . $this->getViewName(true) . ' where oxparentid = ' . $sParentIdQuoted . ' and ' . $this->getSqlActiveSnippet(true) . ' and oxstock > 0 ';
4512  $iStock = (float) $oDb->getOne($sQ, false, false);
4513 
4514  $sQ = 'update oxarticles set oxvarstock = ' . $iStock . ' where oxid = ' . $sParentIdQuoted;
4515  $oDb->execute($sQ);
4516 
4517  //now lets update category counts
4518  //first detect stock status change for this article (to or from 0)
4519  if ($iStock < 0) {
4520  $iStock = 0;
4521  }
4522  if ($iOldStock < 0) {
4523  $iOldStock = 0;
4524  }
4525  if ($this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock) {
4526  //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
4527  // so far we leave it like this but later we could move all count resets to one or two functions
4528  $this->_onChangeResetCounts($sParentID, $iVendorID, $iManufacturerID);
4529  }
4530  }
4531  }
4532 
4538  protected function _onChangeStockResetCount($sOxid)
4539  {
4540  $myConfig = $this->getConfig();
4541 
4542  if ($myConfig->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2 &&
4543  ($this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value) <= 0
4544  ) {
4545 
4546  $this->_onChangeResetCounts($sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
4547  }
4548  }
4549 
4555  protected function _onChangeUpdateVarCount($sParentID)
4556  {
4557  if ($sParentID) {
4558  $oDb = oxDb::getDb();
4559  $sParentIdQuoted = $oDb->quote($sParentID);
4560  $sQ = "select count(*) as varcount from oxarticles where oxparentid = {$sParentIdQuoted}";
4561  $iVarCount = (int) $oDb->getOne($sQ, false, false);
4562 
4563  $sQ = "update oxarticles set oxvarcount = {$iVarCount} where oxid = {$sParentIdQuoted}";
4564  $oDb->execute($sQ);
4565  }
4566  }
4567 
4573  protected function _setVarMinMaxPrice($sParentId)
4574  {
4575  if ($sParentId) {
4577  $sQ = '
4578  SELECT
4579  MIN( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varminprice`,
4580  MAX( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varmaxprice`
4581  FROM ' . $this->getViewName(true) . ' AS `oxarticles`
4582  LEFT JOIN ' . $this->getViewName(true) . ' AS `p` ON ( `p`.`oxid` = `oxarticles`.`oxparentid` AND `p`.`oxprice` > 0 )
4583  WHERE ' . $this->getSqlActiveSnippet(true) . '
4584  AND ( `oxarticles`.`oxparentid` = ' . $oDb->quote($sParentId) . ' )';
4585  $oDb->setFetchMode(oxDb::FETCH_MODE_ASSOC);
4586  $aPrices = $oDb->getRow($sQ, false, false);
4587  if (!is_null($aPrices['varminprice']) || !is_null($aPrices['varmaxprice'])) {
4588  $sQ = '
4589  UPDATE `oxarticles`
4590  SET
4591  `oxvarminprice` = ' . $oDb->quote($aPrices['varminprice']) . ',
4592  `oxvarmaxprice` = ' . $oDb->quote($aPrices['varmaxprice']) . '
4593  WHERE
4594  `oxid` = ' . $oDb->quote($sParentId);
4595  } else {
4596  $sQ = '
4597  UPDATE `oxarticles`
4598  SET
4599  `oxvarminprice` = `oxprice`,
4600  `oxvarmaxprice` = `oxprice`
4601  WHERE
4602  `oxid` = ' . $oDb->quote($sParentId);
4603  }
4604  $oDb->execute($sQ);
4605  }
4606  }
4607 
4615  protected function _hasMasterImage($iIndex)
4616  {
4617  $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
4618 
4619  if ($sPicName == "nopic.jpg" || $sPicName == "") {
4620  return false;
4621  }
4622  if ($this->isVariant() &&
4623  $this->getParentArticle() &&
4624  $this->getParentArticle()->{"oxarticles__oxpic" . $iIndex}->value == $this->{"oxarticles__oxpic" . $iIndex}->value
4625  ) {
4626  return false;
4627  }
4628 
4629  $sMasterPic = 'product/' . $iIndex . "/" . $sPicName;
4630 
4631  if ($this->getConfig()->getMasterPicturePath($sMasterPic)) {
4632  return true;
4633  }
4634 
4635  return false;
4636  }
4637 
4643  protected function _isPriceViewModeNetto()
4644  {
4645  $blResult = (bool) $this->getConfig()->getConfigParam('blShowNetPrice');
4646  $oUser = $this->getArticleUser();
4647  if ($oUser) {
4648  $blResult = $oUser->isPriceViewModeNetto();
4649  }
4650 
4651  return $blResult;
4652  }
4653 
4654 
4662  protected function _getPriceObject($blCalculationModeNetto = null)
4663  {
4664  $oPrice = oxNew('oxPrice');
4665 
4666  if ($blCalculationModeNetto === null) {
4667  $blCalculationModeNetto = $this->_isPriceViewModeNetto();
4668  }
4669 
4670  if ($blCalculationModeNetto) {
4671  $oPrice->setNettoPriceMode();
4672  } else {
4673  $oPrice->setBruttoPriceMode();
4674  }
4675 
4676  return $oPrice;
4677  }
4678 
4679 
4687  protected function _getPriceForView($oPrice)
4688  {
4689  if ($this->_isPriceViewModeNetto()) {
4690  $dPrice = $oPrice->getNettoPrice();
4691  } else {
4692  $dPrice = $oPrice->getBruttoPrice();
4693  }
4694 
4695  return $dPrice;
4696  }
4697 
4698 
4708  protected function _preparePrice($dPrice, $dVat, $blCalculationModeNetto = null)
4709  {
4710  if ($blCalculationModeNetto === null) {
4711  $blCalculationModeNetto = $this->_isPriceViewModeNetto();
4712  }
4713 
4714  $oCurrency = $this->getConfig()->getActShopCurrencyObject();
4715 
4716  $blEnterNetPrice = $this->getConfig()->getConfigParam('blEnterNetPrice');
4717  if ($blCalculationModeNetto && !$blEnterNetPrice) {
4718  $dPrice = round(oxPrice::brutto2Netto($dPrice, $dVat), $oCurrency->decimal);
4719  } elseif (!$blCalculationModeNetto && $blEnterNetPrice) {
4720  $dPrice = round(oxPrice::netto2Brutto($dPrice, $dVat), $oCurrency->decimal);
4721  }
4722 
4723  return $dPrice;
4724  }
4725 
4731  protected function _getUserPriceSufix()
4732  {
4733  $sPriceSuffix = '';
4734  $oUser = $this->getArticleUser();
4735 
4736  if ($oUser) {
4737  if ($oUser->inGroup('oxidpricea')) {
4738  $sPriceSuffix = 'a';
4739  } elseif ($oUser->inGroup('oxidpriceb')) {
4740  $sPriceSuffix = 'b';
4741  } elseif ($oUser->inGroup('oxidpricec')) {
4742  $sPriceSuffix = 'c';
4743  }
4744  }
4745 
4746  return $sPriceSuffix;
4747  }
4748 
4749 
4755  protected function _getPrice()
4756  {
4757  $sPriceSuffix = $this->_getUserPriceSufix();
4758  if ($sPriceSuffix === '') {
4759  $dPrice = $this->oxarticles__oxprice->value;
4760  } else {
4761  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4762  $dPrice = ($this->{oxarticles__oxprice . $sPriceSuffix}->value != 0) ? $this->{oxarticles__oxprice . $sPriceSuffix}->value : $this->oxarticles__oxprice->value;
4763  } else {
4764  $dPrice = $this->{oxarticles__oxprice . $sPriceSuffix}->value;
4765  }
4766  }
4767 
4768  return $dPrice;
4769  }
4770 
4771 
4777  protected function _getVarMinPrice()
4778  {
4779  if ($this->_dVarMinPrice === null) {
4780  $dPrice = null;
4781 
4782 
4783  if (is_null($dPrice)) {
4784  $sPriceSuffix = $this->_getUserPriceSufix();
4785  if ($sPriceSuffix === '') {
4786  $dPrice = $this->oxarticles__oxvarminprice->value;
4787  } else {
4788  $sSql = 'SELECT ';
4789  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4790  $sSql .= 'MIN( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varminprice` ';
4791  } else {
4792  $sSql .= 'MIN(`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
4793  }
4794 
4795  $sSql .= ' FROM ' . $this->getViewName(true) . '
4796  WHERE ' . $this->getSqlActiveSnippet(true) . '
4797  AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
4798 
4799  $dPrice = oxDb::getDb()->getOne($sSql);
4800  }
4801  }
4802 
4803  $this->_dVarMinPrice = $dPrice;
4804  }
4805 
4806  return $this->_dVarMinPrice;
4807  }
4808 
4814  protected function _getSubShopVarMinPrice()
4815  {
4816  $myConfig = $this->getConfig();
4817  $sShopId = $myConfig->getShopId();
4818  if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
4819  $sPriceSuffix = $this->_getUserPriceSufix();
4820  $sSql = 'SELECT ';
4821  if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4822  $sSql .= 'MIN(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varminprice` ';
4823  } else {
4824  $sSql .= 'MIN(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
4825  }
4826  $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
4827  INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
4828  WHERE ' . $this->getSqlActiveSnippet(true) . '
4829  AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
4830  AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
4831  $dPrice = oxDb::getDb()->getOne($sSql);
4832  }
4833 
4834  return $dPrice;
4835  }
4836 
4842  protected function _getVarMaxPrice()
4843  {
4844  if ($this->_dVarMaxPrice === null) {
4845 
4846  $dPrice = null;
4847 
4848  if (is_null($dPrice)) {
4849  $sPriceSuffix = $this->_getUserPriceSufix();
4850  if ($sPriceSuffix === '') {
4851  $dPrice = $this->oxarticles__oxvarmaxprice->value;
4852  } else {
4853  $sSql = 'SELECT ';
4854  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4855  $sSql .= 'MAX( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varmaxprice` ';
4856  } else {
4857  $sSql .= 'MAX(`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
4858  }
4859 
4860  $sSql .= ' FROM ' . $this->getViewName(true) . '
4861  WHERE ' . $this->getSqlActiveSnippet(true) . '
4862  AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
4863 
4864  $dPrice = oxDb::getDb()->getOne($sSql);
4865  }
4866  }
4867 
4868  $this->_dVarMaxPrice = $dPrice;
4869  }
4870 
4871  return $this->_dVarMaxPrice;
4872  }
4873 
4879  protected function _getSubShopVarMaxPrice()
4880  {
4881  $myConfig = $this->getConfig();
4882  $sShopId = $myConfig->getShopId();
4883  if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
4884  $sPriceSuffix = $this->_getUserPriceSufix();
4885  $sSql = 'SELECT ';
4886  if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4887  $sSql .= 'MAX(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varmaxprice` ';
4888  } else {
4889  $sSql .= 'MAX(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
4890  }
4891  $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
4892  INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
4893  WHERE ' . $this->getSqlActiveSnippet(true) . '
4894  AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
4895  AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
4896  $dPrice = oxDb::getDb()->getOne($sSql);
4897  }
4898 
4899  return $dPrice;
4900  }
4901 
4909  protected function _loadFromDb($sOXID)
4910  {
4911 
4912  $sSelect = $this->buildSelectString(array($this->getViewName() . ".oxid" => $sOXID));
4913 
4914 
4915  $aData = oxDb::getDb(oxDb::FETCH_MODE_ASSOC)->getRow($sSelect);
4916 
4917  return $aData;
4918  }
4919 
4925  protected function _updateParentDependFields()
4926  {
4927  $oDb = oxDb::getDb();
4928 
4929  foreach ($this->_getCopyParentFields() as $sField) {
4930  $sValue = isset($this->$sField->value) ? $this->$sField->value : 0;
4931  $sSqlSets[] = '`' . str_replace('oxarticles__', '', $sField) . '` = ' . $oDb->quote($sValue);
4932  }
4933 
4934  $sSql = "UPDATE `oxarticles` SET ";
4935  $sSql .= implode(', ', $sSqlSets) . '';
4936  $sSql .= " WHERE `oxparentid` = " . $oDb->quote($this->getId());
4937 
4938  return $oDb->execute($sSql);
4939  }
4940 
4941 
4947  protected function _getCopyParentFields()
4948  {
4949  return $this->_aCopyParentField;
4950  }
4951 
4955  protected function _assignParentDependFields()
4956  {
4957  $sParent = $this->getParentArticle();
4958  if ($sParent) {
4959  foreach ($this->_getCopyParentFields() as $sField) {
4960  $this->$sField = new oxField($sParent->$sField->value);
4961  }
4962  }
4963  }
4964 
4965 
4966 
4970  protected function _saveSortingFieldValuesOnLoad()
4971  {
4972  $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
4973  $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
4974 
4975  foreach ($aSortingFields as $sField) {
4976  $sFullField = $this->_getFieldLongName($sField);
4977  $this->_aSortingFieldsOnLoad[$sFullField] = $this->$sFullField->value;
4978  }
4979  }
4980 }