OXID eShop CE  4.9.11
 All Classes 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 define('OXARTICLE_LINKTYPE_RECOMM', 5);
10 
17 class oxArticle extends oxI18n implements oxIArticle, oxIUrl
18 {
19 
20 
26  protected $_sClassName = 'oxarticle';
27 
33  protected $_blUseLazyLoading = true;
34 
40  protected $_sItemKey;
41 
48  protected $_blCalcPrice = true;
49 
55  protected $_oPrice = null;
56 
57 
63  protected $_dVarMinPrice = null;
64 
70  protected $_dVarMaxPrice = null;
71 
77  protected $_dArticleVat = null;
78 
84  protected $_aPersistParam = null;
85 
91  protected $_blNotBuyable = false;
92 
99  protected $_blLoadVariants = true;
100 
106  protected $_aVariants = null;
107 
114 
123  protected $_blNotBuyableParent = false;
124 
125 
129  protected $_blHasVariants = false;
130 
134  protected $_blHasMdVariants = false;
135 
141  protected $_blIsOnComparisonList = false;
142 
148  protected $_oUser = null;
149 
156  protected $_blLoadPrice = true;
157 
164  protected $_fPricePerUnit = null;
165 
169  protected $_blLoadParentData = false;
170 
174  protected $_blAllowEmptyParentId = false;
175 
179  protected $_blSkipAssign = false;
180 
186  protected $_blSkipDiscounts = null;
187 
192  protected $_oAttributeList = null;
193 
194 
200  protected $_blIsRangePrice = null;
201 
207  protected $_aMediaUrls = null;
208 
214  static protected $_aLoadedParents;
215 
221  static protected $_aSelList;
222 
228  protected $_aDispSelList;
229 
235  protected $_blIsSeoObject = true;
236 
242  protected $_oAmountPriceList = null;
243 
252  protected $_iLinkType = 0;
253 
259  protected $_aStdUrls = array();
260 
266  protected $_aSeoUrls = array();
267 
273  protected $_aSeoAddParams = array();
274 
280  protected $_aStdAddParams = array();
281 
287  protected $_sDynImageDir = null;
288 
294  protected $_sMoreDetailLink = null;
295 
301  protected $_sToBasketLink = null;
302 
308  protected $_iStockStatusOnLoad = null;
309 
315  protected $_aSortingFieldsOnLoad = array();
316 
322  protected $_iStockStatus = null;
323 
329  protected $_oTPrice = null;
330 
336  protected $_oAmountPriceInfo = null;
337 
343  protected $_dAmountPrice = null;
344 
350  protected static $_aArticleManufacturers = array();
351 
357  protected static $_aArticleVendors = array();
358 
364  protected static $_aArticleCats = array();
365 
371  protected $_aNonCopyParentFields = array('oxarticles__oxinsert',
372  'oxarticles__oxtimestamp',
373  'oxarticles__oxnid',
374  'oxarticles__oxid',
375  'oxarticles__oxparentid');
376 
382  protected $_aCopyParentField = array('oxarticles__oxnonmaterial',
383  'oxarticles__oxfreeshipping',
384  'oxarticles__oxisdownloadable',
385  'oxarticles__oxshowcustomagreement');
386 
392  protected $_oMdVariants = null;
393 
399  protected $_oLongDesc = null;
400 
408  protected $_aVariantSelections = array();
409 
415  protected static $_aSelections = array();
416 
422  protected static $_aCategoryCache = null;
423 
429  protected static $_blHasAmountPrice = null;
430 
436  protected $_aArticleFiles = null;
437 
443  protected $_blCanUpdateAnyField = null;
444 
453  public function __construct($aParams = null)
454  {
455  if ($aParams && is_array($aParams)) {
456  foreach ($aParams as $sParam => $mValue) {
457  $this->$sParam = $mValue;
458  }
459  }
461  $this->init('oxarticles');
462  }
463 
472  public function __get($sName)
473  {
474  $this->$sName = parent::__get($sName);
475  if ($this->$sName) {
476  // since the field could have been loaded via lazy loading
477  $this->_assignParentFieldValue($sName);
478  }
479 
480  return $this->$sName;
481  }
482 
489  public function __set($sName, $sValue)
490  {
491  parent::__set($sName, $sValue);
492  }
493 
500  public function isInList()
501  {
502  return $this->_isInList();
503  }
504 
512  public function setId($sId = null)
513  {
514  $sId = parent::setId($sId);
515 
516  // TODO: in oxbase::setId make it to check if exists and update, not recreate, then delete this overload
517  $this->oxarticles__oxnid = $this->oxarticles__oxid;
518 
519  return $sId;
520  }
521 
531  public function getActiveCheckQuery($blForceCoreTable = null)
532  {
533  $sTable = $this->getViewName($blForceCoreTable);
534 
535  // check if article is still active
536  $sQ = " $sTable.oxactive = 1 ";
537 
538  // enabled time range check ?
539  if ($this->getConfig()->getConfigParam('blUseTimeCheck')) {
540  $sDate = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
541  $sQ = "( $sQ or ( $sTable.oxactivefrom < '$sDate' and $sTable.oxactiveto > '$sDate' ) ) ";
542  }
543 
544  return $sQ;
545  }
546 
560  public function getStockCheckQuery($blForceCoreTable = null)
561  {
562  $myConfig = $this->getConfig();
563  $sTable = $this->getViewName($blForceCoreTable);
564 
565  $sQ = "";
566 
567  //do not check for variants
568  if ($myConfig->getConfigParam('blUseStock')) {
569  $sQ = " and ( $sTable.oxstockflag != 2 or ( $sTable.oxstock + $sTable.oxvarstock ) > 0 ) ";
570  //V #M513: When Parent article is not purchasable, it's visibility should be displayed in shop only if any of Variants is available.
571  if (!$myConfig->getConfigParam('blVariantParentBuyable')) {
572  $sTimeCheckQ = '';
573  if ($myConfig->getConfigParam('blUseTimeCheck')) {
574  $sDate = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
575  $sTimeCheckQ = " or ( art.oxactivefrom < '$sDate' and art.oxactiveto > '$sDate' )";
576  }
577  $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 ) ) ";
578  }
579  }
580 
581  return $sQ;
582  }
583 
595  public function getVariantsQuery($blRemoveNotOrderables, $blForceCoreTable = null)
596  {
597  $sTable = $this->getViewName($blForceCoreTable);
598  $sQ = " and $sTable.oxparentid = '" . $this->getId() . "' ";
599 
600  //checking if variant is active and stock status
601  if ($this->getConfig()->getConfigParam('blUseStock')) {
602  $sQ .= " and ( $sTable.oxstock > 0 or ( $sTable.oxstock <= 0 and $sTable.oxstockflag != 2 ";
603  if ($blRemoveNotOrderables) {
604  $sQ .= " and $sTable.oxstockflag != 3 ";
605  }
606  $sQ .= " ) ) ";
607  }
608 
609  return $sQ;
610  }
611 
617  public function getUnitQuantity()
618  {
619  return $this->oxarticles__oxunitquantity->value;
620  }
621 
627  public function getSize()
628  {
629  $dSize = $this->oxarticles__oxlength->value *
630  $this->oxarticles__oxwidth->value *
631  $this->oxarticles__oxheight->value;
632 
633  return $dSize;
634  }
635 
641  public function getWeight()
642  {
643  return $this->oxarticles__oxweight->value;
644  }
645 
653  public function getSqlActiveSnippet($blForceCoreTable = null)
654  {
655  // check if article is still active
656  $sQ = $this->getActiveCheckQuery($blForceCoreTable);
657 
658  // stock and variants check
659  $sQ .= $this->getStockCheckQuery($blForceCoreTable);
660 
661 
662  return "( $sQ ) ";
663  }
664 
670  public function setSkipAssign($blSkipAssign)
671  {
672  $this->_blSkipAssign = $blSkipAssign;
673  }
674 
678  public function disablePriceLoad()
679  {
680  $this->_blLoadPrice = false;
681  }
682 
686  public function enablePriceLoad()
687  {
688  $this->_blLoadPrice = true;
689  }
690 
696  public function getItemKey()
697  {
698  return $this->_sItemKey;
699  }
700 
706  public function setItemKey($sItemKey)
707  {
708  $this->_sItemKey = $sItemKey;
709  }
710 
716  public function setNoVariantLoading($blLoadVariants)
717  {
718  $this->_blLoadVariants = !$blLoadVariants;
719  }
720 
726  public function isBuyable()
727  {
728  if ($this->_blNotBuyableParent) {
729  return false;
730  }
731 
732  return !$this->_blNotBuyable;
733  }
734 
740  public function getPersParams()
741  {
742  return $this->_aPersistParam;
743  }
744 
750  public function isOnComparisonList()
751  {
753  }
754 
760  public function setOnComparisonList($blOnList)
761  {
762  $this->_blIsOnComparisonList = $blOnList;
763  }
764 
770  public function setLoadParentData($blLoadParentData)
771  {
772  $this->_blLoadParentData = $blLoadParentData;
773  }
774 
780  public function getLoadParentData()
781  {
783  }
784 
785 
793  public function isMultilingualField($sFieldName)
794  {
795  switch ($sFieldName) {
796  case "oxlongdesc":
797  case "oxtags":
798  return true;
799  }
800 
801  return parent::isMultilingualField($sFieldName);
802  }
803 
810  public function getFUnitPrice()
811  {
812  if ($this->_fPricePerUnit == null) {
813  if ($oPrice = $this->getUnitPrice()) {
814  if ($dPrice = $this->_getPriceForView($oPrice)) {
815  $this->_fPricePerUnit = oxRegistry::getLang()->formatCurrency($dPrice);
816  }
817  }
818  }
819 
820  return $this->_fPricePerUnit;
821  }
822 
828  public function getUnitPrice()
829  {
830  // Performance
831  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
832  return;
833  }
834 
835  $oPrice = null;
836  if ((double) $this->getUnitQuantity() && $this->oxarticles__oxunitname->value) {
837  $oPrice = clone $this->getPrice();
838  $oPrice->divide((double) $this->getUnitQuantity());
839  }
840 
841  return $oPrice;
842  }
843 
851  public function getFMinPrice()
852  {
853  $sPrice = '';
854  if ($oPrice = $this->getMinPrice()) {
855  $dPrice = $this->_getPriceForView($oPrice);
856  $sPrice = oxRegistry::getLang()->formatCurrency($dPrice);
857  }
858 
859  return $sPrice;
860  }
861 
869  public function getFVarMinPrice()
870  {
871  $sPrice = '';
872  if ($oPrice = $this->getVarMinPrice()) {
873  $dPrice = $this->_getPriceForView($oPrice);
874  $sPrice = oxRegistry::getLang()->formatCurrency($dPrice);
875  }
876 
877  return $sPrice;
878  }
879 
885  public function getVarMinPrice()
886  {
887  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
888  return;
889  }
890 
891  $oPrice = null;
892  $dPrice = $this->_getVarMinPrice();
893 
894  $dPrice = $this->_preparePrice($dPrice, $this->getArticleVat());
895 
896 
897  $oPrice = $this->_getPriceObject();
898  $oPrice->setPrice($dPrice);
899  $this->_calculatePrice($oPrice);
900 
901 
902  return $oPrice;
903  }
904 
910  public function getMinPrice()
911  {
912  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
913  return;
914  }
915 
916  $oPrice = null;
917  $dPrice = $this->_getPrice();
918  if ($this->_getVarMinPrice() !== null && $dPrice > $this->_getVarMinPrice()) {
919  $dPrice = $this->_getVarMinPrice();
920  }
921 
922  $dPrice = $this->_preparePrice($dPrice, $this->getArticleVat());
923 
924 
925  $oPrice = $this->_getPriceObject();
926  $oPrice->setPrice($dPrice);
927  $this->_calculatePrice($oPrice);
928 
929  return $oPrice;
930  }
931 
937  public function isRangePrice()
938  {
939  if ($this->_blIsRangePrice === null) {
940 
941  $this->setRangePrice(false);
942 
943  if ($this->_hasAnyVariant()) {
944  $dPrice = $this->_getPrice();
945  $dMinPrice = $this->_getVarMinPrice();
946  $dMaxPrice = $this->_getVarMaxPrice();
947 
948  if ($dMinPrice != $dMaxPrice) {
949  $this->setRangePrice();
950  } elseif (!$this->isParentNotBuyable() && $dMinPrice != $dPrice) {
951  $this->setRangePrice();
952  }
953  }
954  }
955 
956  return $this->_blIsRangePrice;
957  }
958 
959 
967  public function setRangePrice($blIsRangePrice = true)
968  {
969  return $this->_blIsRangePrice = $blIsRangePrice;
970  }
971 
977  public function isVisible()
978  {
979 
980  // admin preview mode
981  if (($blCanPreview = oxRegistry::getUtils()->canPreview()) !== null) {
982  return $blCanPreview;
983  }
984 
985  // active ?
986  $sNow = date('Y-m-d H:i:s');
987  if (!$this->oxarticles__oxactive->value &&
988  ($this->oxarticles__oxactivefrom->value > $sNow ||
989  $this->oxarticles__oxactiveto->value < $sNow
990  )
991  ) {
992  return false;
993  }
994 
995  // stock flags
996  if ($this->getConfig()->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2) {
997  $iOnStock = $this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value;
998  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
999  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
1000  }
1001  if ($iOnStock <= 0) {
1002  return false;
1003  }
1004  }
1005 
1006  return true;
1007  }
1008 
1017  public function assign($aRecord)
1018  {
1019  startProfile('articleAssign');
1020 
1021  // load object from database
1022  parent::assign($aRecord);
1023 
1024  $this->oxarticles__oxnid = $this->oxarticles__oxid;
1025 
1026  // check for simple article.
1027  if ($this->_blSkipAssign) {
1028  return;
1029  }
1030 
1031  $this->_assignParentFieldValues();
1032  $this->_assignNotBuyableParent();
1033 
1034 
1035  $this->_assignStock();
1036  $this->_assignPersistentParam();
1037  $this->_assignDynImageDir();
1038  $this->_assignComparisonListFlag();
1039 
1040 
1041  stopProfile('articleAssign');
1042  }
1043 
1044 
1055  public function load($sOXID)
1056  {
1057  // A. #1325 resetting to avoid problems when reloading (details etc)
1058  $this->_blNotBuyableParent = false;
1059 
1060 
1061  $aData = $this->_loadFromDb($sOXID);
1062 
1063  if ($aData) {
1064  $this->assign($aData);
1065 
1067 
1068  $this->_iStockStatusOnLoad = $this->_iStockStatus;
1069 
1070  $this->_isLoaded = true;
1071 
1072  return true;
1073  }
1074 
1075  return false;
1076  }
1077 
1083  public function hasSortingFieldsChanged()
1084  {
1085  $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
1086  $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
1087  $blChanged = false;
1088  foreach ($aSortingFields as $sField) {
1089  $sParameterName = 'oxarticles__' . $sField;
1090  if ($this->$sParameterName->value !== $this->_aSortingFieldsOnLoad[$sParameterName]) {
1091  $blChanged = true;
1092  break;
1093  }
1094  }
1095 
1096  return $blChanged;
1097  }
1098 
1099 
1105  public function addToRatingAverage($iRating)
1106  {
1107  $dOldRating = $this->oxarticles__oxrating->value;
1108  $dOldCnt = $this->oxarticles__oxratingcnt->value;
1109  $this->oxarticles__oxrating->setValue(($dOldRating * $dOldCnt + $iRating) / ($dOldCnt + 1));
1110  $this->oxarticles__oxratingcnt->setValue($dOldCnt + 1);
1111  $dRating = ($dOldRating * $dOldCnt + $iRating) / ($dOldCnt + 1);
1112  $dRatingCnt = (int) ($dOldCnt + 1);
1113  // oxarticles.oxtimestamp = oxarticles.oxtimestamp to keep old timestamp value
1114  $oDb = oxDb::getDb();
1115  $oDb->execute('update oxarticles set oxarticles.oxrating = ' . $dRating . ',oxarticles.oxratingcnt = ' . $dRatingCnt . ', oxarticles.oxtimestamp = oxarticles.oxtimestamp where oxarticles.oxid = ' . $oDb->quote($this->getId()));
1116 
1117  }
1118 
1124  public function setRatingAverage($iRating)
1125  {
1126  $this->oxarticles__oxrating = new oxField($iRating);
1127  }
1128 
1134  public function setRatingCount($iRatingCnt)
1135  {
1136  $this->oxarticles__oxratingcnt = new oxField($iRatingCnt);
1137  }
1138 
1146  public function getArticleRatingAverage($blIncludeVariants = false)
1147  {
1148  if (!$blIncludeVariants) {
1149  return round($this->oxarticles__oxrating->value, 1);
1150  } else {
1151  $oRating = oxNew('oxRating');
1152 
1153  return $oRating->getRatingAverage($this->getId(), 'oxarticle', $this->_getVariantsIds());
1154  }
1155  }
1156 
1164  public function getArticleRatingCount($blIncludeVariants = false)
1165  {
1166  if (!$blIncludeVariants) {
1167  return $this->oxarticles__oxratingcnt->value;
1168  } else {
1169  $oRating = oxNew('oxRating');
1170 
1171  return $oRating->getRatingCount($this->getId(), 'oxarticle', $this->_getVariantsIds());
1172  }
1173  }
1174 
1175 
1181  public function getReviews()
1182  {
1183  $aIds = array($this->getId());
1184 
1185  if ($this->oxarticles__oxparentid->value) {
1186  $aIds[] = $this->oxarticles__oxparentid->value;
1187  }
1188 
1189  // showing variant reviews ..
1190  if ($this->getConfig()->getConfigParam('blShowVariantReviews')) {
1191  $aAdd = $this->_getVariantsIds();
1192  if (is_array($aAdd)) {
1193  $aIds = array_merge($aIds, $aAdd);
1194  }
1195  }
1196 
1197  $oReview = oxNew('oxreview');
1198  $oRevs = $oReview->loadList('oxarticle', $aIds);
1199 
1200  //if no review found, return null
1201  if ($oRevs->count() < 1) {
1202  return null;
1203  }
1204 
1205  return $oRevs;
1206  }
1207 
1213  public function getCrossSelling()
1214  {
1215  $oCrosslist = oxNew("oxarticlelist");
1216  $oCrosslist->loadArticleCrossSell($this->oxarticles__oxid->value);
1217  if ($oCrosslist->count()) {
1218  return $oCrosslist;
1219  }
1220  }
1221 
1227  public function getAccessoires()
1228  {
1229  $myConfig = $this->getConfig();
1230 
1231  // Performance
1232  if (!$myConfig->getConfigParam('bl_perfLoadAccessoires')) {
1233  return;
1234  }
1235 
1236  $oAcclist = oxNew("oxarticlelist");
1237  $oAcclist->setSqlLimit(0, $myConfig->getConfigParam('iNrofCrossellArticles'));
1238  $oAcclist->loadArticleAccessoires($this->oxarticles__oxid->value);
1239 
1240  if ($oAcclist->count()) {
1241  return $oAcclist;
1242  }
1243  }
1244 
1250  public function getSimilarProducts()
1251  {
1252  // Performance
1253  $myConfig = $this->getConfig();
1254  if (!$myConfig->getConfigParam('bl_perfLoadSimilar')) {
1255  return;
1256  }
1257 
1258  // Check configured number of similar products (bug #6062)
1259  if($myConfig->getConfigParam('iNrofSimilarArticles') < 1) {
1260  return;
1261  }
1262 
1263  $sArticleTable = $this->getViewName();
1264 
1265  $sAttribs = '';
1266  $iCnt = 0;
1267  $this->_getAttribsString($sAttribs, $iCnt);
1268 
1269  if (!$sAttribs) {
1270  return null;
1271  }
1272 
1273  $aList = $this->_getSimList($sAttribs, $iCnt);
1274 
1275  if (count($aList)) {
1276  uasort($aList, 'cmpart');
1277 
1278  $sSearch = $this->_generateSimListSearchStr($sArticleTable, $aList);
1279 
1280  $oSimilarlist = oxNew('oxarticlelist');
1281  $oSimilarlist->setSqlLimit(0, $myConfig->getConfigParam('iNrofSimilarArticles'));
1282  $oSimilarlist->selectString($sSearch);
1283 
1284  return $oSimilarlist;
1285  }
1286  }
1287 
1294  {
1295  // Performance
1296  $myConfig = $this->getConfig();
1297  if (!$myConfig->getConfigParam('bl_perfLoadCustomerWhoBoughtThis')) {
1298  return;
1299  }
1300 
1301  // selecting products that fits
1302  $sQ = $this->_generateSearchStrForCustomerBought();
1303 
1304  $oArticles = oxNew('oxarticlelist');
1305  $oArticles->setSqlLimit(0, $myConfig->getConfigParam('iNrofCustomerWhoArticles'));
1306  $oArticles->selectString($sQ);
1307  if ($oArticles->count()) {
1308  return $oArticles;
1309  }
1310  }
1311 
1318  public function loadAmountPriceInfo()
1319  {
1320  $myConfig = $this->getConfig();
1321  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice || !$this->_blCalcPrice || !$this->hasAmountPrice()) {
1322  return array();
1323  }
1324 
1325  if ($this->_oAmountPriceInfo === null) {
1326  $this->_oAmountPriceInfo = array();
1327  if (count(($aAmPriceList = $this->_getAmountPriceList()->getArray()))) {
1328  $this->_oAmountPriceInfo = $this->_fillAmountPriceList($aAmPriceList);
1329  }
1330  }
1331 
1332  return $this->_oAmountPriceInfo;
1333  }
1334 
1342  public function getSelectLists($sKeyPrefix = null)
1343  {
1344  //#1468C - more then one article in basket with different selectlist...
1345  //optionall function parameter $sKeyPrefix added, used only in basket.php
1346  $sKey = $this->getId();
1347  if (isset($sKeyPrefix)) {
1348  $sKey = $sKeyPrefix . '__' . $sKey;
1349  }
1350 
1351  if (!isset(self::$_aSelList[$sKey])) {
1352  $oDb = oxDb::getDb();
1353  $sSLViewName = getViewName('oxselectlist');
1354 
1355  $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
1356  where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
1357 
1358  // all selectlists this article has
1359  $oLists = oxNew('oxlist');
1360  $oLists->init('oxselectlist');
1361  $oLists->selectString(sprintf($sQ, $oDb->quote($this->getId())));
1362 
1363  //#1104S if this is variant ant it has no selectlists, trying with parent
1364  if ($oLists->count() == 0 && $this->oxarticles__oxparentid->value) {
1365  $oLists->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
1366  }
1367 
1368  // We do not need to calculate price here as there are method to get current article vat
1369  /*if ( $this->getPrice() != null ) {
1370  $dVat = $this->getPrice()->getVat();
1371  }*/
1372  $dVat = $this->getArticleVat();
1373 
1374  $iCnt = 0;
1375  self::$_aSelList[$sKey] = array();
1376  foreach ($oLists as $oSelectlist) {
1377  self::$_aSelList[$sKey][$iCnt] = $oSelectlist->getFieldList($dVat);
1378  self::$_aSelList[$sKey][$iCnt]['name'] = $oSelectlist->oxselectlist__oxtitle->value;
1379  $iCnt++;
1380  }
1381  }
1382 
1383  return self::$_aSelList[$sKey];
1384  }
1385 
1391  public function getVariantsCount()
1392  {
1393  return $this->oxarticles__oxvarcount->value;
1394  }
1395 
1401  public function hasMdVariants()
1402  {
1403  return $this->_blHasMdVariants;
1404  }
1405 
1411  public function hasIntangibleAgreement()
1412  {
1413  return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxnonmaterial->value && !$this->hasDownloadableAgreement();
1414  }
1415 
1421  public function hasDownloadableAgreement()
1422  {
1423  return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxisdownloadable->value;
1424  }
1425 
1435  public function getVariantSelections($aFilterIds = null, $sActVariantId = null, $iLimit = 0)
1436  {
1437  $iLimit = (int) $iLimit;
1438  if (!isset($this->_aVariantSelections[$iLimit])) {
1439  $aVariantSelections = false;
1440  if ($this->oxarticles__oxvarcount->value) {
1441  $oVariants = $this->getVariants(false);
1442  $aVariantSelections = oxNew("oxVariantHandler")->buildVariantSelections($this->oxarticles__oxvarname->getRawValue(), $oVariants, $aFilterIds, $sActVariantId, $iLimit);
1443 
1444  if (!empty($oVariants) && empty($aVariantSelections['rawselections'])) {
1445  $aVariantSelections = false;
1446  }
1447  }
1448  $this->_aVariantSelections[$iLimit] = $aVariantSelections;
1449  }
1450 
1451  return $this->_aVariantSelections[$iLimit];
1452  }
1453 
1462  public function getSelections($iLimit = null, $aFilter = null)
1463  {
1464  $sId = $this->getId() . ((int) $iLimit);
1465  if (!array_key_exists($sId, self::$_aSelections)) {
1466 
1467  $oDb = oxDb::getDb();
1468  $sSLViewName = getViewName('oxselectlist');
1469 
1470  $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
1471  where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
1472 
1473  if (($iLimit = (int) $iLimit)) {
1474  $sQ .= " limit $iLimit ";
1475  }
1476 
1477  // vat value for price
1478  $dVat = 0;
1479  if (($oPrice = $this->getPrice()) != null) {
1480  $dVat = $oPrice->getVat();
1481  }
1482 
1483  // all selectlists this article has
1484  $oList = oxNew('oxlist');
1485  $oList->init('oxselectlist');
1486  $oList->getBaseObject()->setVat($dVat);
1487  $oList->selectString(sprintf($sQ, $oDb->quote($this->getId())));
1488 
1489  //#1104S if this is variant and it has no selectlists, trying with parent
1490  if ($oList->count() == 0 && $this->oxarticles__oxparentid->value) {
1491  $oList->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
1492  }
1493 
1494  self::$_aSelections[$sId] = $oList->count() ? $oList : false;
1495  }
1496 
1497  if (self::$_aSelections[$sId]) {
1498  // marking active from filter
1499  $aFilter = ($aFilter === null) ? oxRegistry::getConfig()->getRequestParameter("sel") : $aFilter;
1500  if ($aFilter) {
1501  $iSelIdx = 0;
1502  foreach (self::$_aSelections[$sId] as $oSelection) {
1503  if (isset($aFilter[$iSelIdx])) {
1504  $oSelection->setActiveSelectionByIndex($aFilter[$iSelIdx]);
1505  }
1506  $iSelIdx++;
1507  }
1508  }
1509  }
1510 
1511  return self::$_aSelections[$sId];
1512  }
1513 
1522  public function getFullVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
1523  {
1524  return $this->_loadVariantList(false, $blRemoveNotOrderables, $blForceCoreTable);
1525  }
1526 
1536  public function getVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
1537  {
1538  return $this->_loadVariantList($this->_isInList(), $blRemoveNotOrderables, $blForceCoreTable);
1539  }
1540 
1546  public function getSimpleVariants()
1547  {
1548  if ($this->oxarticles__oxvarcount->value) {
1549  return $this->getVariants();
1550  }
1551  }
1552 
1561  public function getAdminVariants($sLanguage = null)
1562  {
1563  $oVariants = oxNew('oxarticlelist');
1564  if (($sId = $this->getId())) {
1565 
1566  $oBaseObj = $oVariants->getBaseObject();
1567 
1568  if (is_null($sLanguage)) {
1569  $oBaseObj->setLanguage(oxRegistry::getLang()->getBaseLanguage());
1570  } else {
1571  $oBaseObj->setLanguage($sLanguage);
1572  }
1573 
1574  $sSql = "select * from " . $oBaseObj->getViewName() . " where oxparentid = '{$sId}' order by oxsort ";
1575  $oVariants->selectString($sSql);
1576 
1577  //if we have variants then depending on config option the parent may be non buyable
1578  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && ($oVariants->count() > 0)) {
1579  //$this->blNotBuyable = true;
1580  $this->_blNotBuyableParent = true;
1581  }
1582  }
1583 
1584  return $oVariants;
1585  }
1586 
1594  public function getCategory()
1595  {
1596  $oCategory = oxNew('oxcategory');
1597  $oCategory->setLanguage($this->getLanguage());
1598 
1599  // variant handling
1600  $sOXID = $this->getId();
1601  if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
1602  $sOXID = $this->oxarticles__oxparentid->value;
1603  }
1604 
1605  if ($sOXID) {
1606  // if the oxcategory instance of this article is not cached
1607  if (!isset($this->_aCategoryCache[$sOXID])) {
1608  startPRofile('getCategory');
1609  $oStr = getStr();
1610  $sWhere = $oCategory->getSqlActiveSnippet();
1611  $sSelect = $this->_generateSearchStr($sOXID);
1612  $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " order by oxobject2category.oxtime limit 1";
1613 
1614  // category not found ?
1615  if (!$oCategory->assignRecord($sSelect)) {
1616 
1617  $sSelect = $this->_generateSearchStr($sOXID, true);
1618  $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " limit 1";
1619 
1620  // looking for price category
1621  if (!$oCategory->assignRecord($sSelect)) {
1622  $oCategory = null;
1623  }
1624  }
1625  // add the category instance to cache
1626  $this->_aCategoryCache[$sOXID] = $oCategory;
1627  stopPRofile('getCategory');
1628  } else {
1629  // if the oxcategory instance is cached
1630  $oCategory = $this->_aCategoryCache[$sOXID];
1631  }
1632  }
1633 
1634  return $oCategory;
1635  }
1636 
1645  public function getCategoryIds($blActCats = false, $blSkipCache = false)
1646  {
1647  $sArticleId = $this->getId();
1648 
1649  if (!isset(self::$_aArticleCats[$sArticleId]) || $blSkipCache) {
1650 
1651  $sSql = $this->_getCategoryIdsSelect($blActCats);
1652  $aCategoryIds = $this->_selectCategoryIds($sSql, 'oxcatnid');
1653 
1654  $sSql = $this->getSqlForPriceCategories();
1655  $aPriceCategoryIds = $this->_selectCategoryIds($sSql, 'oxid');
1656 
1657  self::$_aArticleCats[$sArticleId] = array_unique(array_merge($aCategoryIds, $aPriceCategoryIds));
1658  }
1659 
1660  return self::$_aArticleCats[$sArticleId];
1661  }
1662 
1672  public function getVendor($blShopCheck = true)
1673  {
1674  if (($sVendorId = $this->getVendorId())) {
1675  $oVendor = oxNew('oxvendor');
1676  } elseif (!$blShopCheck && $this->oxarticles__oxvendorid->value) {
1677  $oVendor = oxNew('oxi18n');
1678  $oVendor->init('oxvendor');
1679  $oVendor->setReadOnly(true);
1680  $sVendorId = $this->oxarticles__oxvendorid->value;
1681  }
1682  if ($sVendorId && $oVendor->load($sVendorId) && $oVendor->oxvendor__oxactive->value) {
1683 
1684  return $oVendor;
1685  }
1686 
1687  return null;
1688  }
1689 
1697  public function getVendorId($blForceReload = false)
1698  {
1699  $sVendorId = false;
1700  if ($this->oxarticles__oxvendorid->value) {
1701  $sVendorId = $this->oxarticles__oxvendorid->value;
1702 
1703  }
1704 
1705  return $sVendorId;
1706  }
1707 
1715  public function getManufacturerId($blForceReload = false)
1716  {
1717  $sManufacturerId = false;
1718  if ($this->oxarticles__oxmanufacturerid->value) {
1719 
1720  $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
1721 
1722  }
1723 
1724  return $sManufacturerId;
1725  }
1726 
1736  public function getManufacturer($blShopCheck = true)
1737  {
1738  $oManufacturer = oxNew('oxmanufacturer');
1739  if (!($sManufacturerId = $this->getManufacturerId()) &&
1740  !$blShopCheck && $this->oxarticles__oxmanufacturerid->value
1741  ) {
1742  $oManufacturer->setReadOnly(true);
1743  $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
1744  }
1745 
1746  if ($sManufacturerId && $oManufacturer->load($sManufacturerId)) {
1747  if (!$this->getConfig()->getConfigParam('bl_perfLoadManufacturerTree')) {
1748  $oManufacturer->setReadOnly(true);
1749  }
1750  $oManufacturer = $oManufacturer->oxmanufacturers__oxactive->value ? $oManufacturer : null;
1751  } else {
1752  $oManufacturer = null;
1753  }
1754 
1755  return $oManufacturer;
1756  }
1757 
1765  public function inCategory($sCatNid)
1766  {
1767  return in_array($sCatNid, $this->getCategoryIds());
1768  }
1769 
1778  public function isAssignedToCategory($sCatId)
1779  {
1780  // variant handling
1781  $sOXID = $this->getId();
1782  if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
1783  $sOXID = $this->oxarticles__oxparentid->value;
1784  }
1785 
1786  $oDb = oxDb::getDb();
1787  $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId);
1788  $sOXID = $oDb->getOne($sSelect);
1789  // article is assigned to passed category!
1790  if (isset($sOXID) && $sOXID) {
1791  return true;
1792  }
1793 
1794  // maybe this category is price category ?
1795  if ($this->getConfig()->getConfigParam('bl_perfLoadPrice') && $this->_blLoadPrice) {
1796  $dPriceFromTo = $this->getPrice()->getBruttoPrice();
1797  if ($dPriceFromTo > 0) {
1798  $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo);
1799  $sOXID = $oDb->getOne($sSelect);
1800  // article is assigned to passed category!
1801  if (isset($sOXID) && $sOXID) {
1802  return true;
1803  }
1804  }
1805  }
1806 
1807  return false;
1808  }
1809 
1815  public function getTPrice()
1816  {
1817  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1818  return;
1819  }
1820 
1821  // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
1822  if ($this->_oTPrice !== null) {
1823  return $this->_oTPrice;
1824  }
1825 
1826  $oPrice = $this->_getPriceObject();
1827 
1828  $dBasePrice = $this->oxarticles__oxtprice->value;
1829  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
1830 
1831  $oPrice->setPrice($dBasePrice);
1832 
1833  $this->_applyVat($oPrice, $this->getArticleVat());
1834  $this->_applyCurrency($oPrice);
1835 
1836  if ($this->isParentNotBuyable()) {
1837  // if parent article is not buyable then compare agains min article variant price
1838  $oPrice2 = $this->getVarMinPrice();
1839  } else {
1840  // else compare against article price
1841  $oPrice2 = $this->getPrice();
1842  }
1843 
1844  if ($oPrice->getPrice() <= $oPrice2->getPrice()) {
1845  // if RRP price is less or equal to comparable price then return
1846  return;
1847  }
1848 
1849  $this->_oTPrice = $oPrice;
1850 
1851  return $this->_oTPrice;
1852  }
1853 
1859  public function skipDiscounts()
1860  {
1861  // already loaded skip discounts config
1862  if ($this->_blSkipDiscounts !== null) {
1863  return $this->_blSkipDiscounts;
1864  }
1865 
1866  if ($this->oxarticles__oxskipdiscounts->value) {
1867  return true;
1868  }
1869 
1870 
1871  $this->_blSkipDiscounts = false;
1872  if (oxRegistry::get("oxDiscountList")->hasSkipDiscountCategories()) {
1873 
1874  $oDb = oxDb::getDb();
1875  $sO2CView = getViewName('oxobject2category', $this->getLanguage());
1876  $sViewName = getViewName('oxcategories', $this->getLanguage());
1877  $sSelect = "select 1 from $sO2CView as $sO2CView left join {$sViewName} on {$sViewName}.oxid = $sO2CView.oxcatnid
1878  where $sO2CView.oxobjectid=" . $oDb->quote($this->getId()) . " and {$sViewName}.oxactive = 1 and {$sViewName}.oxskipdiscounts = '1' ";
1879  $this->_blSkipDiscounts = ($oDb->getOne($sSelect) == 1);
1880  }
1881 
1882  return $this->_blSkipDiscounts;
1883  }
1884 
1890  public function setPrice(oxPrice $oPrice)
1891  {
1892  $this->_oPrice = $oPrice;
1893  }
1894 
1903  public function getBasePrice($dAmount = 1)
1904  {
1905  // override this function if you want e.g. different prices
1906  // for diff. user groups.
1907 
1908  // Performance
1909  $myConfig = $this->getConfig();
1910  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1911  return;
1912  }
1913 
1914  // GroupPrice or DB price ajusted by AmountPrice
1915  $dPrice = $this->_getAmountPrice($dAmount);
1916 
1917 
1918  return $dPrice;
1919  }
1920 
1928  public function getPrice($dAmount = 1)
1929  {
1930  $myConfig = $this->getConfig();
1931  // Performance
1932  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1933  return;
1934  }
1935 
1936  // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
1937  if ($dAmount != 1 || $this->_oPrice === null) {
1938 
1939  // module
1940  $dBasePrice = $this->getBasePrice($dAmount);
1941  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
1942 
1943  $oPrice = $this->_getPriceObject();
1944 
1945  $oPrice->setPrice($dBasePrice);
1946 
1947  // price handling
1948  if (!$this->_blCalcPrice && $dAmount == 1) {
1949  return $this->_oPrice = $oPrice;
1950  }
1951 
1952  $this->_calculatePrice($oPrice);
1953  if ($dAmount != 1) {
1954  return $oPrice;
1955  }
1956 
1957  $this->_oPrice = $oPrice;
1958  }
1959 
1960  return $this->_oPrice;
1961  }
1962 
1968  public function setArticleUser($oUser)
1969  {
1970  $this->_oUser = $oUser;
1971  }
1972 
1978  public function getArticleUser()
1979  {
1980  if ($this->_oUser) {
1981  return $this->_oUser;
1982  }
1983 
1984  return $this->getUser();
1985  }
1986 
1996  public function getBasketPrice($dAmount, $aSelList, $oBasket)
1997  {
1998  $oUser = $oBasket->getBasketUser();
1999  $this->setArticleUser($oUser);
2000 
2001  $oBasketPrice = $this->_getPriceObject($oBasket->isCalculationModeNetto());
2002 
2003  // get base price
2004  $dBasePrice = $this->getBasePrice($dAmount);
2005 
2006  $dBasePrice = $this->_modifySelectListPrice($dBasePrice, $aSelList);
2007  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat(), $oBasket->isCalculationModeNetto());
2008 
2009  // applying select list price
2010 
2011  // setting price
2012  $oBasketPrice->setPrice($dBasePrice);
2013 
2014  $dVat = oxRegistry::get("oxVatSelector")->getBasketItemVat($this, $oBasket);
2015  $this->_calculatePrice($oBasketPrice, $dVat);
2016 
2017  // returning final price object
2018  return $oBasketPrice;
2019  }
2020 
2029  public function delete($sOXID = null)
2030  {
2031  if (!$sOXID) {
2032  $sOXID = $this->getId();
2033  }
2034  if (!$sOXID) {
2035  return false;
2036  }
2037 
2038 
2039 
2040  // #2339 delete first variants before deleting parent product
2041  $this->_deleteVariantRecords($sOXID);
2042  $this->load($sOXID);
2043  $this->_deletePics();
2044  $this->_onChangeResetCounts($sOXID, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
2045 
2046  // delete self
2047  parent::delete($sOXID);
2048 
2049  $rs = $this->_deleteRecords($sOXID);
2050 
2051  oxRegistry::get("oxSeoEncoderArticle")->onDeleteArticle($this);
2052 
2053  $this->onChange(ACTION_DELETE, $sOXID, $this->oxarticles__oxparentid->value);
2054 
2055  return $rs->EOF;
2056  }
2057 
2066  public function reduceStock($dAmount, $blAllowNegativeStock = false)
2067  {
2068  $this->beforeUpdate();
2069 
2070  $iStockCount = $this->oxarticles__oxstock->value - $dAmount;
2071  if (!$blAllowNegativeStock && ($iStockCount < 0)) {
2072  $dAmount += $iStockCount;
2073  $iStockCount = 0;
2074  }
2075  $this->oxarticles__oxstock = new oxField($iStockCount);
2076 
2077  $oDb = oxDb::getDb();
2078  $oDb->execute('update oxarticles set oxarticles.oxstock = ' . $oDb->quote($iStockCount) . ' where oxarticles.oxid = ' . $oDb->quote($this->getId()));
2079  $this->onChange(ACTION_UPDATE_STOCK);
2080 
2081  return $dAmount;
2082  }
2083 
2092  public function updateSoldAmount($dAmount = 0)
2093  {
2094  if (!$dAmount) {
2095  return;
2096  }
2097 
2098  // article is not variant - should be updated current amount
2099  if (!$this->oxarticles__oxparentid->value) {
2100  //updating by SQL query, due to wrong behaviour if saving article using not admin mode
2101  $dAmount = (double) $dAmount;
2102  $oDb = oxDb::getDb();
2103  $rs = $oDb->execute("update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $dAmount where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
2104  } elseif ($this->oxarticles__oxparentid->value) {
2105  // article is variant - should be updated this article parent amount
2106  $oUpdateArticle = $this->getParentArticle();
2107  if ($oUpdateArticle) {
2108  $oUpdateArticle->updateSoldAmount($dAmount);
2109  }
2110  }
2111 
2112  return $rs;
2113  }
2114 
2120  public function disableReminder()
2121  {
2122  $oDb = oxDb::getDb();
2123 
2124  return $oDb->execute("update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
2125  }
2126 
2132  public function save()
2133  {
2134  $this->_assignParentDependFields();
2135 
2136  if (($blRet = parent::save())) {
2137  // saving long description
2138  $this->_saveArtLongDesc();
2139  }
2140 
2141  return $blRet;
2142  }
2143 
2147  public function resetParent()
2148  {
2149  $sParentId = $this->oxarticles__oxparentid->value;
2150  $this->oxarticles__oxparentid = new oxField('', oxField::T_RAW);
2151  $this->_blAllowEmptyParentId = true;
2152  $this->save();
2153  $this->_blAllowEmptyParentId = false;
2154 
2155  if ($sParentId !== '') {
2156  $this->onChange(ACTION_UPDATE, null, $sParentId);
2157  }
2158  }
2159 
2160 
2167  public function getPictureGallery()
2168  {
2169  $myConfig = $this->getConfig();
2170 
2171  //initialize
2172  $blMorePic = false;
2173  $aArtPics = array();
2174  $aArtIcons = array();
2175  $iActPicId = 1;
2176  $sActPic = $this->getPictureUrl($iActPicId);
2177 
2178  if (oxRegistry::getConfig()->getRequestParameter('actpicid')) {
2179  $iActPicId = oxRegistry::getConfig()->getRequestParameter('actpicid');
2180  }
2181 
2182  $oStr = getStr();
2183  $iCntr = 0;
2184  $iPicCount = $myConfig->getConfigParam('iPicCount');
2185  $blCheckActivePicId = true;
2186 
2187  for ($i = 1; $i <= $iPicCount; $i++) {
2188  $sPicVal = $this->getPictureUrl($i);
2189  $sIcoVal = $this->getIconUrl($i);
2190  if (!$oStr->strstr($sIcoVal, 'nopic_ico.jpg') && !$oStr->strstr($sIcoVal, 'nopic.jpg') &&
2191  !$oStr->strstr($sPicVal, 'nopic_ico.jpg') && !$oStr->strstr($sPicVal, 'nopic.jpg') &&
2192  $sPicVal !== null
2193  ) {
2194  if ($iCntr) {
2195  $blMorePic = true;
2196  }
2197  $aArtIcons[$i] = $sIcoVal;
2198  $aArtPics[$i] = $sPicVal;
2199  $iCntr++;
2200 
2201  if ($iActPicId == $i) {
2202  $sActPic = $sPicVal;
2203  $blCheckActivePicId = false;
2204  }
2205 
2206  } elseif ($blCheckActivePicId && $iActPicId <= $i) {
2207  // if picture is empty, setting active pic id to next
2208  // picture
2209  $iActPicId++;
2210  }
2211  }
2212 
2213  $blZoomPic = false;
2214  $aZoomPics = array();
2215  $iZoomPicCount = $myConfig->getConfigParam('iPicCount');
2216 
2217  for ($j = 1, $c = 1; $j <= $iZoomPicCount; $j++) {
2218  $sVal = $this->getZoomPictureUrl($j);
2219 
2220  if ($sVal && !$oStr->strstr($sVal, 'nopic.jpg')) {
2221  $blZoomPic = true;
2222  $aZoomPics[$c]['id'] = $c;
2223  $aZoomPics[$c]['file'] = $sVal;
2224  //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
2225  if (!$sVal) {
2226  $aZoomPics[$c]['file'] = "nopic.jpg";
2227  }
2228  $c++;
2229  }
2230  }
2231 
2232  $aPicGallery = array('ActPicID' => $iActPicId,
2233  'ActPic' => $sActPic,
2234  'MorePics' => $blMorePic,
2235  'Pics' => $aArtPics,
2236  'Icons' => $aArtIcons,
2237  'ZoomPic' => $blZoomPic,
2238  'ZoomPics' => $aZoomPics);
2239 
2240  return $aPicGallery;
2241  }
2242 
2256  public function onChange($sAction = null, $sOXID = null, $sParentID = null)
2257  {
2258  $myConfig = $this->getConfig();
2259 
2260  if (!isset($sOXID)) {
2261  if ($this->getId()) {
2262  $sOXID = $this->getId();
2263  }
2264  if (!isset ($sOXID)) {
2265  $sOXID = $this->oxarticles__oxid->value;
2266  }
2267  if ($this->oxarticles__oxparentid->value) {
2268  $sParentID = $this->oxarticles__oxparentid->value;
2269  }
2270  }
2271  if (!isset($sOXID)) {
2272  return;
2273  }
2274 
2275  //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
2276  if ($myConfig->getConfigParam('blUseStock')) {
2277  //if article has variants then updating oxvarstock field
2278  //getting parent id
2279  if (!isset($sParentID)) {
2280  $oDb = oxDb::getDb();
2281  $sQ = 'select oxparentid from oxarticles where oxid = ' . $oDb->quote($sOXID);
2282  $sParentID = $oDb->getOne($sQ);
2283  }
2284  //if we have parent id then update stock
2285  if ($sParentID) {
2286  $this->_onChangeUpdateStock($sParentID);
2287  }
2288  }
2289  //if we have parent id then update count
2290  //update count even if blUseStock is not active
2291  if ($sParentID) {
2292  $this->_onChangeUpdateVarCount($sParentID);
2293  }
2294 
2295  $sId = ($sParentID) ? $sParentID : $sOXID;
2296  $this->_setVarMinMaxPrice($sId);
2297 
2298  $this->_updateParentDependFields();
2299 
2300  // resetting articles count cache if stock has changed and some
2301  // articles goes offline (M:1448)
2302  if ($sAction === ACTION_UPDATE_STOCK) {
2303  $this->_assignStock();
2304  $this->_onChangeStockResetCount($sOXID);
2305  }
2306 
2307  }
2308 
2315  public function getCustomVAT()
2316  {
2317  if (isset($this->oxarticles__oxvat->value)) {
2318  return $this->oxarticles__oxvat->value;
2319  }
2320  }
2321 
2330  public function checkForStock($dAmount, $dArtStockAmount = 0)
2331  {
2332  $myConfig = $this->getConfig();
2333  if (!$myConfig->getConfigParam('blUseStock')) {
2334  return true;
2335  }
2336 
2338  // fetching DB info as its up-to-date
2339  $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = ' . $oDb->quote($this->getId());
2340  $rs = $oDb->select($sQ);
2341 
2342  $iOnStock = 0;
2343  $iStockFlag = 0;
2344  if ($rs !== false && $rs->recordCount() > 0) {
2345  $iOnStock = $rs->fields['oxstock'] - $dArtStockAmount;
2346  $iStockFlag = $rs->fields['oxstockflag'];
2347 
2348  // foreign stock is also always considered as on stock
2349  if ($iStockFlag == 1 || $iStockFlag == 4) {
2350  return true;
2351  }
2352  if (!$myConfig->getConfigParam('blAllowUnevenAmounts')) {
2353  $iOnStock = floor($iOnStock);
2354  }
2355  }
2356  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
2357  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
2358  }
2359  if ($iOnStock >= $dAmount) {
2360  return true;
2361  } else {
2362  if ($iOnStock > 0) {
2363  return $iOnStock;
2364  } else {
2365  $oEx = oxNew('oxArticleInputException');
2366  $oEx->setMessage('ERROR_MESSAGE_ARTICLE_ARTICLE_NOT_BUYABLE');
2367  oxRegistry::get("oxUtilsView")->addErrorToDisplay($oEx);
2368 
2369  return false;
2370  }
2371  }
2372  }
2373 
2374 
2380  public function getLongDescription()
2381  {
2382  if ($this->_oLongDesc === null) {
2383  // initializing
2384  $this->_oLongDesc = new oxField();
2385 
2386 
2387  // choosing which to get..
2388  $sOxid = $this->getId();
2389  $sViewName = getViewName('oxartextends', $this->getLanguage());
2390 
2391  $oDb = oxDb::getDb();
2392  $sDbValue = $oDb->getOne("select oxlongdesc from {$sViewName} where oxid = " . $oDb->quote($sOxid));
2393 
2394  if ($sDbValue != false) {
2395  $this->_oLongDesc->setValue($sDbValue, oxField::T_RAW);
2396  } elseif ($this->oxarticles__oxparentid->value) {
2397  if (!$this->isAdmin() || $this->_blLoadParentData) {
2398  $oParent = $this->getParentArticle();
2399  if ($oParent) {
2400  $this->_oLongDesc->setValue($oParent->getLongDescription()->getRawValue(), oxField::T_RAW);
2401  }
2402  }
2403  }
2404  }
2405 
2406  return $this->_oLongDesc;
2407  }
2408 
2415  public function getLongDesc()
2416  {
2417  return oxRegistry::get("oxUtilsView")->parseThroughSmarty($this->getLongDescription()->getRawValue(), $this->getId() . $this->getLanguage(), null, true);
2418  }
2419 
2427  public function setArticleLongDesc($sDesc)
2428  {
2429 
2430  // setting current value
2431  $this->_oLongDesc = new oxField($sDesc, oxField::T_RAW);
2432  $this->oxarticles__oxlongdesc = new oxField($sDesc, oxField::T_RAW);
2433  }
2434 
2440  public function getAttributes()
2441  {
2442  if ($this->_oAttributeList === null) {
2443  $this->_oAttributeList = oxNew('oxattributelist');
2444  $this->_oAttributeList->loadAttributes($this->getId(), $this->getParentId());
2445  }
2446 
2447  return $this->_oAttributeList;
2448  }
2449 
2456  {
2457  if ($this->_oAttributeList === null) {
2458  $this->_oAttributeList = oxNew('oxattributelist');
2459  $this->_oAttributeList->loadAttributesDisplayableInBasket($this->getId(), $this->getParentId());
2460  }
2461 
2462  return $this->_oAttributeList;
2463  }
2464 
2465 
2472  public function appendLink($sAddParams, $iLang = null)
2473  {
2474  if ($sAddParams) {
2475  if ($iLang === null) {
2476  $iLang = $this->getLanguage();
2477  }
2478 
2479  $this->_aSeoAddParams[$iLang] = isset($this->_aSeoAddParams[$iLang]) ? $this->_aSeoAddParams[$iLang] . "&amp;" : "";
2480  $this->_aSeoAddParams[$iLang] .= $sAddParams;
2481  }
2482  }
2483 
2492  public function getBaseSeoLink($iLang, $blMain = false)
2493  {
2495  $oEncoder = oxRegistry::get("oxSeoEncoderArticle");
2496  if (!$blMain) {
2497  return $oEncoder->getArticleUrl($this, $iLang, $this->getLinkType());
2498  }
2499 
2500  return $oEncoder->getArticleMainUrl($this, $iLang);
2501  }
2502 
2511  public function getLink($iLang = null, $blMain = false)
2512  {
2513  if (!oxRegistry::getUtils()->seoIsActive()) {
2514  return $this->getStdLink($iLang);
2515  }
2516 
2517  if ($iLang === null) {
2518  $iLang = $this->getLanguage();
2519  }
2520 
2521  $iLinkType = $this->getLinkType();
2522  if (!isset($this->_aSeoUrls[$iLang][$iLinkType])) {
2523  $this->_aSeoUrls[$iLang][$iLinkType] = $this->getBaseSeoLink($iLang, $blMain);
2524  }
2525 
2526  $sUrl = $this->_aSeoUrls[$iLang][$iLinkType];
2527  if (isset($this->_aSeoAddParams[$iLang])) {
2528  $sUrl .= ((strpos($sUrl . $this->_aSeoAddParams[$iLang], '?') === false) ? '?' : '&amp;') . $this->_aSeoAddParams[$iLang];
2529  }
2530 
2531  return $sUrl;
2532  }
2533 
2542  public function getMainLink($iLang = null)
2543  {
2544  return $this->getLink($iLang, true);
2545  }
2546 
2552  public function setLinkType($iType)
2553  {
2554  // resetting details link, to force new
2555  $this->_sDetailLink = null;
2556 
2557  // setting link type
2558  $this->_iLinkType = (int) $iType;
2559  }
2560 
2566  public function getLinkType()
2567  {
2568  return $this->_iLinkType;
2569  }
2570 
2577  public function appendStdLink($sAddParams, $iLang = null)
2578  {
2579  if ($sAddParams) {
2580  if ($iLang === null) {
2581  $iLang = $this->getLanguage();
2582  }
2583 
2584  $this->_aStdAddParams[$iLang] = isset($this->_aStdAddParams[$iLang]) ? $this->_aStdAddParams[$iLang] . "&amp;" : "";
2585  $this->_aStdAddParams[$iLang] .= $sAddParams;
2586  }
2587  }
2588 
2598  public function getBaseStdLink($iLang, $blAddId = true, $blFull = true)
2599  {
2600  $sUrl = '';
2601  if ($blFull) {
2602  //always returns shop url, not admin
2603  $sUrl = $this->getConfig()->getShopUrl($iLang, false);
2604  }
2605 
2606  $sUrl .= "index.php?cl=details" . ($blAddId ? "&amp;anid=" . $this->getId() : "");
2607 
2608  return $sUrl . (isset($this->_aStdAddParams[$iLang]) ? "&amp;" . $this->_aStdAddParams[$iLang] : "");
2609  }
2610 
2619  public function getStdLink($iLang = null, $aParams = array())
2620  {
2621  if ($iLang === null) {
2622  $iLang = $this->getLanguage();
2623  }
2624 
2625  if (!isset($this->_aStdUrls[$iLang])) {
2626  $this->_aStdUrls[$iLang] = $this->getBaseStdLink($iLang);
2627  }
2628 
2629  return oxRegistry::get("oxUtilsUrl")->processUrl($this->_aStdUrls[$iLang], true, $aParams, $iLang);
2630  }
2631 
2637  public function getMediaUrls()
2638  {
2639  if ($this->_aMediaUrls === null) {
2640  $this->_aMediaUrls = oxNew("oxlist");
2641  $this->_aMediaUrls->init("oxmediaurl");
2642  $this->_aMediaUrls->getBaseObject()->setLanguage($this->getLanguage());
2643 
2644  $sViewName = getViewName("oxmediaurls", $this->getLanguage());
2645  $sQ = "select * from {$sViewName} where oxobjectid = '" . $this->getId() . "'";
2646  $this->_aMediaUrls->selectString($sQ);
2647  }
2648 
2649  return $this->_aMediaUrls;
2650  }
2651 
2657  public function getDynImageDir()
2658  {
2659  return $this->_sDynImageDir;
2660  }
2661 
2667  public function getDispSelList()
2668  {
2669  if ($this->_aDispSelList === null) {
2670  if ($this->getConfig()->getConfigParam('bl_perfLoadSelectLists') && $this->getConfig()->getConfigParam('bl_perfLoadSelectListsInAList')) {
2671  $this->_aDispSelList = $this->getSelectLists();
2672  }
2673  }
2674 
2675  return $this->_aDispSelList;
2676  }
2677 
2683  public function getMoreDetailLink()
2684  {
2685  if ($this->_sMoreDetailLink == null) {
2686 
2687  // and assign special article values
2688  $this->_sMoreDetailLink = $this->getConfig()->getShopHomeURL() . 'cl=moredetails';
2689 
2690  // not always it is okey, as not all the time active category is the same as primary article cat.
2691  if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
2692  $this->_sMoreDetailLink .= '&amp;cnid=' . $sActCat;
2693  }
2694  $this->_sMoreDetailLink .= '&amp;anid=' . $this->getId();
2695  $this->_sMoreDetailLink = $this->_sMoreDetailLink;
2696  }
2697 
2698  return $this->_sMoreDetailLink;
2699  }
2700 
2706  public function getToBasketLink()
2707  {
2708  if ($this->_sToBasketLink == null) {
2709  $myConfig = $this->getConfig();
2710 
2711  if (oxRegistry::getUtils()->isSearchEngine()) {
2712  $this->_sToBasketLink = $this->getLink();
2713  } else {
2714  // and assign special article values
2715  $this->_sToBasketLink = $myConfig->getShopHomeURL();
2716 
2717  // override some classes as these should never showup
2718  $sActClass = oxRegistry::getConfig()->getRequestParameter('cl');
2719  if ($sActClass == 'thankyou') {
2720  $sActClass = 'basket';
2721  }
2722  $this->_sToBasketLink .= 'cl=' . $sActClass;
2723 
2724  // this is not very correct
2725  if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
2726  $this->_sToBasketLink .= '&amp;cnid=' . $sActCat;
2727  }
2728 
2729  $this->_sToBasketLink .= '&amp;fnc=tobasket&amp;aid=' . $this->getId() . '&amp;anid=' . $this->getId();
2730 
2731  if ($sTpl = basename(oxRegistry::getConfig()->getRequestParameter('tpl'))) {
2732  $this->_sToBasketLink .= '&amp;tpl=' . $sTpl;
2733  }
2734  }
2735  }
2736 
2737  return $this->_sToBasketLink;
2738  }
2739 
2745  public function getStockStatus()
2746  {
2747  return $this->_iStockStatus;
2748  }
2749 
2755  public function getDeliveryDate()
2756  {
2757  if ($this->oxarticles__oxdelivery->value != '0000-00-00') {
2758  return oxRegistry::get("oxUtilsDate")->formatDBDate($this->oxarticles__oxdelivery->value);
2759  }
2760 
2761  return false;
2762  }
2763 
2771  public function getFTPrice()
2772  {
2773  // module
2774  if ($oPrice = $this->getTPrice()) {
2775  if ($dPrice = $this->_getPriceForView($oPrice)) {
2776  return oxRegistry::getLang()->formatCurrency($dPrice);
2777  }
2778  }
2779  }
2780 
2788  public function getFPrice()
2789  {
2790  if ($oPrice = $this->getPrice()) {
2791  $dPrice = $this->_getPriceForView($oPrice);
2792 
2793  return oxRegistry::getLang()->formatCurrency($dPrice);
2794  }
2795  }
2796 
2801  public function resetRemindStatus()
2802  {
2803  if ($this->oxarticles__oxremindactive->value == 2 &&
2804  $this->oxarticles__oxremindamount->value <= $this->oxarticles__oxstock->value
2805  ) {
2806  $this->oxarticles__oxremindactive->value = 1;
2807  }
2808  }
2809 
2817  public function getFNetPrice()
2818  {
2819  if ($oPrice = $this->getPrice()) {
2820  return oxRegistry::getLang()->formatCurrency($oPrice->getNettoPrice());
2821  }
2822  }
2823 
2829  public function isParentNotBuyable()
2830  {
2832  }
2833 
2839  public function isNotBuyable()
2840  {
2841  return $this->_blNotBuyable;
2842  }
2843 
2849  public function setBuyableState($blBuyable = false)
2850  {
2851  $this->_blNotBuyable = !$blBuyable;
2852  }
2853 
2859  public function setSelectlist($aSelList)
2860  {
2861  $this->_aDispSelList = $aSelList;
2862  }
2863 
2871  public function getPictureUrl($iIndex = 1)
2872  {
2873  if ($iIndex) {
2874  $sImgName = false;
2875  if (!$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
2876  $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
2877  }
2878 
2879  $sSize = $this->getConfig()->getConfigParam('aDetailImageSizes');
2880 
2881  return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
2882  }
2883  }
2884 
2893  public function getIconUrl($iIndex = 0)
2894  {
2895  $sImgName = false;
2896  $sDirname = "product/1/";
2897  if ($iIndex && !$this->_isFieldEmpty("oxarticles__oxpic{$iIndex}")) {
2898  $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
2899  $sDirname = "product/{$iIndex}/";
2900  } elseif (!$this->_isFieldEmpty("oxarticles__oxicon")) {
2901  $sImgName = basename($this->oxarticles__oxicon->value);
2902  $sDirname = "product/icon/";
2903  } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
2904  $sImgName = basename($this->oxarticles__oxpic1->value);
2905  }
2906 
2907  $sSize = $this->getConfig()->getConfigParam('sIconsize');
2908 
2909  $sIconUrl = oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, $iIndex);
2910 
2911  return $sIconUrl;
2912  }
2913 
2921  public function getThumbnailUrl($bSsl = null)
2922  {
2923  $sImgName = false;
2924  $sDirname = "product/1/";
2925  if (!$this->_isFieldEmpty("oxarticles__oxthumb")) {
2926  $sImgName = basename($this->oxarticles__oxthumb->value);
2927  $sDirname = "product/thumb/";
2928  } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
2929  $sImgName = basename($this->oxarticles__oxpic1->value);
2930  }
2931 
2932  $sSize = $this->getConfig()->getConfigParam('sThumbnailsize');
2933 
2934  return oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, 0, $bSsl);
2935  }
2936 
2944  public function getZoomPictureUrl($iIndex = '')
2945  {
2946  $iIndex = (int) $iIndex;
2947  if ($iIndex > 0 && !$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
2948  $sImgName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
2949  $sSize = $this->getConfig()->getConfigParam("sZoomImageSize");
2950 
2951  return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
2952  }
2953  }
2954 
2960  public function applyVats(oxPrice $oPrice)
2961  {
2962  $this->_applyVAT($oPrice, $this->getArticleVat());
2963  }
2964 
2970  public function applyDiscountsForVariant($oPrice)
2971  {
2972  // apply discounts
2973  if (!$this->skipDiscounts()) {
2974  $oDiscountList = oxRegistry::get("oxDiscountList");
2975  $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
2976 
2977  reset($aDiscounts);
2978  foreach ($aDiscounts as $oDiscount) {
2979  $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
2980  }
2981  $oPrice->calculateDiscount();
2982  }
2983  }
2984 
2990  public function getParentArticle()
2991  {
2992  if (($sParentId = $this->oxarticles__oxparentid->value)) {
2993  $sIndex = $sParentId . "_" . $this->getLanguage();
2994  if (!isset(self::$_aLoadedParents[$sIndex])) {
2995  self::$_aLoadedParents[$sIndex] = oxNew('oxarticle');
2996  self::$_aLoadedParents[$sIndex]->_blLoadPrice = false;
2997  self::$_aLoadedParents[$sIndex]->_blLoadVariants = false;
2998 
2999  if (!self::$_aLoadedParents[$sIndex]->loadInLang($this->getLanguage(), $sParentId)) {
3000  //return false in case parent product failed to load
3001  self::$_aLoadedParents[$sIndex] = false;
3002  }
3003  }
3004 
3005  return self::$_aLoadedParents[$sIndex];
3006  }
3007  }
3008 
3012  public function updateVariantsRemind()
3013  {
3014  // check if it is parent article
3015  if (!$this->isVariant() && $this->_hasAnyVariant()) {
3016  $oDb = oxDb::getDb();
3017  $sOxId = $oDb->quote($this->getId());
3018  $sOxShopId = $oDb->quote($this->getShopId());
3019  $iRemindActive = $oDb->quote($this->oxarticles__oxremindactive->value);
3020  $sUpdate = "
3021  update oxarticles
3022  set oxremindactive = $iRemindActive
3023  where oxparentid = $sOxId and
3024  oxshopid = $sOxShopId
3025  ";
3026  $oDb->execute($sUpdate);
3027  }
3028  }
3029 
3036  public function getProductId()
3037  {
3038  return $this->getId();
3039  }
3040 
3046  public function getParentId()
3047  {
3048  return $this->oxarticles__oxparentid->value;
3049  }
3050 
3056  public function isOrderArticle()
3057  {
3058  return false;
3059  }
3060 
3066  public function isVariant()
3067  {
3068  return (bool) (isset($this->oxarticles__oxparentid) ? $this->oxarticles__oxparentid->value : false);
3069  }
3070 
3076  public function isMdVariant()
3077  {
3078  $oMdVariant = oxNew("oxVariantHandler");
3079 
3080  return $oMdVariant->isMdVariant($this);
3081  }
3082 
3090  public function getSqlForPriceCategories($sFields = '')
3091  {
3092  if (!$sFields) {
3093  $sFields = 'oxid';
3094  }
3095  $sSelectWhere = "select $sFields from " . $this->_getObjectViewName('oxcategories') . " where";
3096  $sQuotedPrice = oxDb::getDb()->quote($this->oxarticles__oxprice->value);
3097 
3098  return "$sSelectWhere oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice"
3099  . " union $sSelectWhere oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice"
3100  . " union $sSelectWhere oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice";
3101  }
3102 
3110  public function inPriceCategory($sCatNid)
3111  {
3112  $oDb = oxDb::getDb();
3113 
3114  $sQuotedPrice = $oDb->quote($this->oxarticles__oxprice->value);
3115  $sQuotedCnid = $oDb->quote($sCatNid);
3116 
3117  return (bool) $oDb->getOne(
3118  "select 1 from " . $this->_getObjectViewName('oxcategories') . " where oxid=$sQuotedCnid and"
3119  . "( (oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice)"
3120  . " or (oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice)"
3121  . " or (oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice)"
3122  . ")"
3123  );
3124  }
3125 
3131  public function getMdVariants()
3132  {
3133  if ($this->_oMdVariants) {
3134  return $this->_oMdVariants;
3135  }
3136 
3137  $oParentArticle = $this->getParentArticle();
3138  if ($oParentArticle) {
3139  $oVariants = $oParentArticle->getVariants();
3140  } else {
3141  $oVariants = $this->getVariants();
3142  }
3143 
3144  $oVariantHandler = oxNew("oxVariantHandler");
3145  $this->_oMdVariants = $oVariantHandler->buildMdVariants($oVariants, $this->getId());
3146 
3147  return $this->_oMdVariants;
3148  }
3149 
3155  public function getMdSubvariants()
3156  {
3157  return $this->getMdVariants()->getMdSubvariants();
3158  }
3159 
3168  public function getPictureFieldValue($sFieldName, $iIndex = null)
3169  {
3170  if ($sFieldName) {
3171  $sFieldName = "oxarticles__" . $sFieldName . $iIndex;
3172 
3173  return $this->$sFieldName->value;
3174  }
3175  }
3176 
3184  public function getMasterZoomPictureUrl($iIndex)
3185  {
3186  $sPicUrl = false;
3187  $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
3188 
3189  if ($sPicName && $sPicName != "nopic.jpg") {
3190  $sPicUrl = $this->getConfig()->getPictureUrl("master/product/" . $iIndex . "/" . $sPicName);
3191  if (!$sPicUrl || basename($sPicUrl) == "nopic.jpg") {
3192  $sPicUrl = false;
3193  }
3194  }
3195 
3196  return $sPicUrl;
3197  }
3198 
3204  public function getUnitName()
3205  {
3206  if ($this->oxarticles__oxunitname->value) {
3207  return oxRegistry::getLang()->translateString($this->oxarticles__oxunitname->value);
3208  }
3209  }
3210 
3218  public function getArticleFiles($blAddFromParent = false)
3219  {
3220  if ($this->_aArticleFiles === null) {
3221 
3222  $this->_aArticleFiles = false;
3223 
3224  $sQ = "SELECT * FROM `oxfiles` WHERE `oxartid` = '" . $this->getId() . "'";
3225 
3226  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && $blAddFromParent) {
3227  $sQ .= " OR `oxartId` = '" . $this->oxarticles__oxparentid->value . "'";
3228  }
3229 
3230  $oArticleFiles = oxNew("oxlist");
3231  $oArticleFiles->init("oxfile");
3232  $oArticleFiles->selectString($sQ);
3233  $this->_aArticleFiles = $oArticleFiles;
3234 
3235  }
3236 
3237  return $this->_aArticleFiles;
3238  }
3239 
3245  public function isDownloadable()
3246  {
3247  return $this->oxarticles__oxisdownloadable->value;
3248  }
3249 
3255  public function hasAmountPrice()
3256  {
3257  if (self::$_blHasAmountPrice === null) {
3258 
3259  self::$_blHasAmountPrice = false;
3260 
3261  $oDb = oxDb::getDb();
3262  $sQ = "SELECT 1 FROM `oxprice2article` LIMIT 1";
3263 
3264  if ($oDb->getOne($sQ)) {
3265  self::$_blHasAmountPrice = true;
3266  }
3267  }
3268 
3269  return self::$_blHasAmountPrice;
3270  }
3271 
3281  protected function _loadVariantList($blSimple, $blRemoveNotOrderables = true, $blForceCoreTable = null)
3282  {
3283  $oVariants = array();
3284  if (($sId = $this->getId())) {
3285  //do not load me as a parent later
3286  self::$_aLoadedParents[$sId . "_" . $this->getLanguage()] = $this;
3287 
3288  $myConfig = $this->getConfig();
3289 
3290  if (!$this->_blLoadVariants ||
3291  (!$this->isAdmin() && !$myConfig->getConfigParam('blLoadVariants')) ||
3292  (!$this->isAdmin() && !$this->oxarticles__oxvarcount->value)
3293  ) {
3294  return $oVariants;
3295  }
3296 
3297  // cache
3298  $sCacheKey = $blSimple ? "simple" : "full";
3299  if ($blRemoveNotOrderables) {
3300  if (isset($this->_aVariants[$sCacheKey])) {
3301  return $this->_aVariants[$sCacheKey];
3302  } else {
3303  $this->_aVariants[$sCacheKey] = & $oVariants;
3304  }
3305  } elseif (!$blRemoveNotOrderables) {
3306  if (isset($this->_aVariantsWithNotOrderables[$sCacheKey])) {
3307  return $this->_aVariantsWithNotOrderables[$sCacheKey];
3308  } else {
3309  $this->_aVariantsWithNotOrderables[$sCacheKey] = & $oVariants;
3310  }
3311  }
3312 
3313  if (($this->_blHasVariants = $this->_hasAnyVariant($blForceCoreTable))) {
3314 
3315  //load simple variants for lists
3316  if ($blSimple) {
3317  $oVariants = oxNew('oxsimplevariantlist');
3318  $oVariants->setParent($this);
3319  } else {
3320  //loading variants
3321  $oVariants = oxNew('oxarticlelist');
3322  $oVariants->getBaseObject()->modifyCacheKey('_variants');
3323  }
3324 
3325  startProfile("selectVariants");
3326  $blUseCoreTable = (bool) $blForceCoreTable;
3327  $oBaseObject = $oVariants->getBaseObject();
3328  $oBaseObject->setLanguage($this->getLanguage());
3329 
3330 
3331  $sArticleTable = $this->getViewName($blUseCoreTable);
3332 
3333  $sSelect = "select " . $oBaseObject->getSelectFields($blUseCoreTable) . " from $sArticleTable where " .
3334  $this->getActiveCheckQuery($blUseCoreTable) .
3335  $this->getVariantsQuery($blRemoveNotOrderables, $blUseCoreTable) .
3336  " order by $sArticleTable.oxsort";
3337  $oVariants->selectString($sSelect);
3338 
3339  //if this is multidimensional variants, make additional processing
3340  if ($myConfig->getConfigParam('blUseMultidimensionVariants')) {
3341  $oMdVariants = oxNew("oxVariantHandler");
3342  $this->_blHasMdVariants = $oMdVariants->isMdVariant($oVariants->current());
3343  }
3344  stopProfile("selectVariants");
3345  }
3346 
3347  //if we have variants then depending on config option the parent may be non buyable
3348  if (!$myConfig->getConfigParam('blVariantParentBuyable') && $this->_blHasVariants) {
3349  $this->_blNotBuyableParent = true;
3350  }
3351 
3352  //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
3353  if (!$myConfig->getConfigParam('blVariantParentBuyable') && count($oVariants) == 0 && $this->_blHasVariants) {
3354  $this->_blNotBuyable = true;
3355  }
3356  }
3357 
3358  return $oVariants;
3359  }
3360 
3369  protected function _selectCategoryIds($sSql, $sField)
3370  {
3372  $aResult = $oDb->getAll($sSql);
3373  $aReturn = array();
3374 
3375 
3376  foreach ($aResult as $aValue) {
3377  $aValue = array_change_key_case($aValue, CASE_LOWER);
3378 
3379 
3380  $aReturn[] = $aValue[$sField];
3381  }
3382 
3383  return $aReturn;
3384  }
3385 
3393  protected function _getCategoryIdsSelect($blActCats = false)
3394  {
3395  $sO2CView = $this->_getObjectViewName('oxobject2category');
3396  $sCatView = $this->_getObjectViewName('oxcategories');
3397 
3398  $sArticleIdSql = 'oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getId());
3399  if ($this->getParentId()) {
3400  $sArticleIdSql = '(' . $sArticleIdSql . ' or oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getParentId()) . ')';
3401  }
3402  $sActiveCategorySql = $blActCats ? $this->_getActiveCategorySelectSnippet() : '';
3403 
3404  $sSelect = "select
3405  oxobject2category.oxcatnid as oxcatnid
3406  from $sO2CView as oxobject2category
3407  left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid
3408  where $sArticleIdSql and oxcategories.oxid is not null and oxcategories.oxactive = 1 $sActiveCategorySql
3409  order by oxobject2category.oxtime";
3410 
3411  return $sSelect;
3412  }
3413 
3419  protected function _getActiveCategorySelectSnippet()
3420  {
3421  $sCatView = $this->_getObjectViewName('oxcategories');
3422  $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 ";
3423 
3424  return $sActiveCategorySql;
3425  }
3426 
3437  protected function _getSelectCatIds($sOXID, $blActCats = false)
3438  {
3439  $sO2CView = $this->_getObjectViewName('oxobject2category');
3440  $sCatView = $this->_getObjectViewName('oxcategories');
3441  $sSelect = "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
3442  $sSelect .= 'where oxobject2category.oxobjectid=' . oxDb::getDb()->quote($sOXID) . ' and oxcategories.oxid is not null and oxcategories.oxactive = 1 ';
3443  if ($blActCats) {
3444  $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 ";
3445  }
3446  $sSelect .= 'order by oxobject2category.oxtime ';
3447 
3448  return $sSelect;
3449  }
3450 
3459  protected function _calculatePrice($oPrice, $dVat = null)
3460  {
3461  // apply VAT only if configuration requires it
3462  if (isset($dVat) || !$this->getConfig()->getConfigParam('bl_perfCalcVatOnlyForBasketOrder')) {
3463  $this->_applyVAT($oPrice, isset($dVat) ? $dVat : $this->getArticleVat());
3464  }
3465 
3466  // apply currency
3467  $this->_applyCurrency($oPrice);
3468  // apply discounts
3469  if (!$this->skipDiscounts()) {
3470  $oDiscountList = oxRegistry::get("oxDiscountList");
3471  $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
3472 
3473  reset($aDiscounts);
3474  foreach ($aDiscounts as $oDiscount) {
3475  $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
3476  }
3477  $oPrice->calculateDiscount();
3478  }
3479 
3480  return $oPrice;
3481  }
3482 
3490  protected function _hasAnyVariant($blForceCoreTable = null)
3491  {
3492  $blHas = false;
3493  if (($sId = $this->getId())) {
3494  if ($this->oxarticles__oxshopid->value == $this->getConfig()->getShopId()) {
3495  $blHas = (bool) $this->oxarticles__oxvarcount->value;
3496  } else {
3497  $sArticleTable = $this->getViewName($blForceCoreTable);
3498  $blHas = (bool) oxDb::getDb()->getOne("select 1 from $sArticleTable where oxparentid='{$sId}'");
3499  }
3500  }
3501 
3502  return $blHas;
3503  }
3504 
3510  protected function _isStockStatusChanged()
3511  {
3512  return $this->_iStockStatus != $this->_iStockStatusOnLoad;
3513  }
3514 
3520  protected function _isVisibilityChanged()
3521  {
3522  return $this->_isStockStatusChanged() && ($this->_iStockStatus == -1 || $this->_iStockStatusOnLoad == -1);
3523  }
3524 
3530  protected function _saveArtLongDesc()
3531  {
3532  $myConfig = $this->getConfig();
3533  $sShopId = $myConfig->getShopID();
3534  if (in_array("oxlongdesc", $this->_aSkipSaveFields)) {
3535  return;
3536  }
3537 
3538  if ($this->_blEmployMultilanguage) {
3539  $sValue = $this->getLongDescription()->getRawValue();
3540  if ($sValue !== null) {
3541  $oArtExt = oxNew('oxI18n');
3542  $oArtExt->init('oxartextends');
3543  $oArtExt->setLanguage((int) $this->getLanguage());
3544  if (!$oArtExt->load($this->getId())) {
3545  $oArtExt->setId($this->getId());
3546  }
3547  $oArtExt->oxartextends__oxlongdesc = new oxField($sValue, oxField::T_RAW);
3548  $oArtExt->save();
3549  }
3550  } else {
3551  $oArtExt = oxNew('oxI18n');
3552  $oArtExt->setEnableMultilang(false);
3553  $oArtExt->init('oxartextends');
3554  $aObjFields = $oArtExt->_getAllFields(true);
3555  if (!$oArtExt->load($this->getId())) {
3556  $oArtExt->setId($this->getId());
3557  }
3558 
3559  foreach ($aObjFields as $sKey => $sValue) {
3560  if (preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey)) {
3561  $sField = $this->_getFieldLongName($sKey);
3562 
3563  if (isset($this->$sField)) {
3564  $sLongDesc = null;
3565  if ($this->$sField instanceof oxField) {
3566  $sLongDesc = $this->$sField->getRawValue();
3567  } elseif (is_object($this->$sField)) {
3568  $sLongDesc = $this->$sField->value;
3569  }
3570  if (isset($sLongDesc)) {
3571  $sAEField = $oArtExt->_getFieldLongName($sKey);
3572  $oArtExt->$sAEField = new oxField($sLongDesc, oxField::T_RAW);
3573  }
3574  }
3575  }
3576  }
3577  $oArtExt->save();
3578  }
3579  }
3580 
3584  protected function _skipSaveFields()
3585  {
3586  $myConfig = $this->getConfig();
3587 
3588  $this->_aSkipSaveFields = array();
3589 
3590  $this->_aSkipSaveFields[] = 'oxtimestamp';
3591  // $this->_aSkipSaveFields[] = 'oxlongdesc';
3592  $this->_aSkipSaveFields[] = 'oxinsert';
3594 
3595  if (!$this->_blAllowEmptyParentId && (!isset($this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '')) {
3596  $this->_aSkipSaveFields[] = 'oxparentid';
3597  }
3598 
3599  }
3600 
3610  protected function _mergeDiscounts($aDiscounts, $aItemDiscounts)
3611  {
3612  foreach ($aItemDiscounts as $sKey => $oDiscount) {
3613  // add prices of the same discounts
3614  if (array_key_exists($sKey, $aDiscounts)) {
3615  $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
3616  } else {
3617  $aDiscounts[$sKey] = $oDiscount;
3618  }
3619  }
3620 
3621  return $aDiscounts;
3622  }
3623 
3629  protected function _getGroupPrice()
3630  {
3631  $sPriceSufix = $this->_getUserPriceSufix();
3632  $sVarName = "oxarticles__oxprice{$sPriceSufix}";
3633  $dPrice = $this->$sVarName->value;
3634 
3635  // #1437/1436C - added config option, and check for zero A,B,C price values
3636  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices') && (double) $dPrice == 0) {
3637  $dPrice = $this->oxarticles__oxprice->value;
3638  }
3639 
3640  return $dPrice;
3641  }
3642 
3651  protected function _getAmountPrice($dAmount = 1)
3652  {
3653  startProfile("_getAmountPrice");
3654 
3655  $dPrice = $this->_getGroupPrice();
3656  $oAmtPrices = $this->_getAmountPriceList();
3657  foreach ($oAmtPrices as $oAmPrice) {
3658  if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
3659  && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
3660  && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value
3661  ) {
3662  $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
3663  }
3664  }
3665 
3666  stopProfile("_getAmountPrice");
3667 
3668  return $dPrice;
3669  }
3670 
3679  protected function _modifySelectListPrice($dPrice, $aChosenList = null)
3680  {
3681  $myConfig = $this->getConfig();
3682  // #690
3683  if ($myConfig->getConfigParam('bl_perfLoadSelectLists') && $myConfig->getConfigParam('bl_perfUseSelectlistPrice')) {
3684 
3685  $aSelLists = $this->getSelectLists();
3686 
3687  foreach ($aSelLists as $key => $aSel) {
3688  if (isset($aChosenList[$key]) && isset($aSel[$aChosenList[$key]])) {
3689  $oSel = $aSel[$aChosenList[$key]];
3690  if ($oSel->priceUnit == 'abs') {
3691  $dPrice += $oSel->price;
3692  } elseif ($oSel->priceUnit == '%') {
3693  $dPrice += oxPrice::percent($dPrice, $oSel->price);
3694  }
3695  }
3696  }
3697  }
3698 
3699  return $dPrice;
3700  }
3701 
3709  protected function _fillAmountPriceList($aAmPriceList)
3710  {
3711  $oLang = oxRegistry::getLang();
3712 
3713  // trying to find lowest price value
3714  foreach ($aAmPriceList as $sId => $oItem) {
3715 
3716  $oItemPrice = $this->_getPriceObject();
3717  if ($oItem->oxprice2article__oxaddabs->value) {
3718 
3719  $dBasePrice = $oItem->oxprice2article__oxaddabs->value;
3720  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
3721 
3722  $oItemPrice->setPrice($dBasePrice);
3723  $this->_calculatePrice($oItemPrice);
3724 
3725  } else {
3726  $dBasePrice = $this->_getGroupPrice();
3727  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
3728  $oItemPrice->setPrice($dBasePrice);
3729  $oItemPrice->subtractPercent($oItem->oxprice2article__oxaddperc->value);
3730  }
3731 
3732 
3733  $aAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency($this->_getPriceForView($oItemPrice));
3734  }
3735 
3736  return $aAmPriceList;
3737  }
3738 
3746  public function getVariantIds($blActiveVariants = true)
3747  {
3748  $aSelect = array();
3749  $sId = $this->getId();
3750  if ($sId) {
3751  $sActiveSqlSnippet = "";
3752  if ($blActiveVariants) {
3753  $sActiveSqlSnippet = " and " . $this->getSqlActiveSnippet(true);
3754  }
3756  $sQ = "select oxid from " . $this->getViewName(true) . " where oxparentid = " . $oDb->quote($sId) .
3757  $sActiveSqlSnippet . " order by oxsort";
3758  $oRs = $oDb->select($sQ);
3759  if ($oRs != false && $oRs->recordCount() > 0) {
3760  while (!$oRs->EOF) {
3761  $aSelect[] = reset($oRs->fields);
3762  $oRs->moveNext();
3763  }
3764  }
3765  }
3766 
3767  return $aSelect;
3768  }
3769 
3779  protected function _getVariantsIds($blActiveVariants = true)
3780  {
3781  return $this->getVariantIds($blActiveVariants);
3782  }
3783 
3789  public function getArticleVat()
3790  {
3791  if (!isset($this->_dArticleVat)) {
3792  $this->_dArticleVat = oxRegistry::get("oxVatSelector")->getArticleVat($this);
3793  }
3794 
3795  return $this->_dArticleVat;
3796  }
3797 
3804  protected function _applyVAT(oxPrice $oPrice, $dVat)
3805  {
3806  startProfile(__FUNCTION__);
3807  $oPrice->setVAT($dVat);
3809  $oVatSelector = oxRegistry::get("oxVatSelector");
3810  if (($dVat = $oVatSelector->getArticleUserVat($this)) !== false) {
3811  $oPrice->setUserVat($dVat);
3812  }
3813  stopProfile(__FUNCTION__);
3814  }
3815 
3822  protected function _applyCurrency(oxPrice $oPrice, $oCur = null)
3823  {
3824  if (!$oCur) {
3825  $oCur = $this->getConfig()->getActShopCurrencyObject();
3826  }
3827 
3828  $oPrice->multiply($oCur->rate);
3829  }
3830 
3831 
3838  protected function _getAttribsString(&$sAttributeSql, &$iCnt)
3839  {
3840  // we do not use lists here as we don't need this overhead right now
3841  $oDb = oxDb::getDb();
3842  $sSelect = 'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid=' . $oDb->quote($this->getId());
3843  if ($this->getParentId()) {
3844  $sSelect .= ' OR oxobject2attribute.oxobjectid=' . $oDb->quote($this->getParentId());
3845  }
3846  $sAttributeSql = '';
3847  $aAttributeIds = $oDb->getCol($sSelect);
3848  if (is_array($aAttributeIds) && count($aAttributeIds)) {
3849  $aAttributeIds = array_unique($aAttributeIds);
3850  $iCnt = count($aAttributeIds);
3851  $sAttributeSql .= 't1.oxattrid IN ( ' . implode(',', $oDb->quoteArray($aAttributeIds)) . ') ';
3852  }
3853  }
3854 
3863  protected function _getSimList($sAttributeSql, $iCnt)
3864  {
3865  // #523A
3866  $iAttrPercent = $this->getConfig()->getConfigParam('iAttributesPercent') / 100;
3867  // 70% same attributes
3868  if (!$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
3869  $iAttrPercent = 0.70;
3870  }
3871  // #1137V iAttributesPercent = 100 doesn't work
3872  $iHitMin = ceil($iCnt * $iAttrPercent);
3873 
3874  $aExcludeIds = array();
3875  $aExcludeIds[] = $this->getId();
3876  if ($this->getParentId()) {
3877  $aExcludeIds[] = $this->getParentId();
3878  }
3879 
3880  // we do not use lists here as we don't need this overhead right now
3881  $sSelect = "select oxobjectid from oxobject2attribute as t1 where
3882  ( $sAttributeSql )
3883  and t1.oxobjectid NOT IN (" . implode(', ', oxDb::getDb()->quoteArray($aExcludeIds)) . ")
3884  group by t1.oxobjectid having count(*) >= $iHitMin LIMIT 0, 20";
3885 
3886  return oxDb::getDb()->getCol($sSelect);
3887  }
3888 
3897  protected function _generateSimListSearchStr($sArticleTable, $aList)
3898  {
3899  $sFieldList = $this->getSelectFields();
3900  $aList = array_slice($aList, 0, $this->getConfig()->getConfigParam('iNrofSimilarArticles'));
3901 
3902  $sSearch = "select $sFieldList from $sArticleTable where " . $this->getSqlActiveSnippet() . " and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
3903 
3904  $sSearch .= implode(',', oxdb::getDb()->quoteArray($aList)) . ')';
3905 
3906  // #524A -- randomizing articles in attribute list
3907  $sSearch .= ' order by rand() ';
3908 
3909  return $sSearch;
3910  }
3911 
3920  protected function _generateSearchStr($sOXID, $blSearchPriceCat = false)
3921  {
3922 
3923  $sCatView = getViewName('oxcategories', $this->getLanguage());
3924  $sO2CView = getViewName('oxobject2category');
3925 
3926  // we do not use lists here as we don't need this overhead right now
3927  if (!$blSearchPriceCat) {
3928  $sSelect = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
3929  {$sCatView}.oxid = oxobject2category.oxcatnid
3930  where oxobject2category.oxobjectid=" . oxDb::getDb()->quote($sOXID) . " and {$sCatView}.oxid is not null ";
3931  } else {
3932  $sSelect = "select {$sCatView}.* from {$sCatView} where
3933  '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
3934  '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
3935  }
3936 
3937  return $sSelect;
3938  }
3939 
3946  {
3947  $sArtTable = $this->getViewName();
3948  $sOrderArtTable = getViewName('oxorderarticles');
3949 
3950  // fetching filter params
3951  $sIn = " '{$this->oxarticles__oxid->value}' ";
3952  if ($this->oxarticles__oxparentid->value) {
3953 
3954  // adding article parent
3955  $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
3956  $sParentIdForVariants = $this->oxarticles__oxparentid->value;
3957 
3958  } else {
3959  $sParentIdForVariants = $this->getId();
3960  }
3961 
3962  // adding variants
3964  $oRs = $oDb->select("select oxid from {$sArtTable} where oxparentid = " . $oDb->quote($sParentIdForVariants) . " and oxid != " . $oDb->quote($this->oxarticles__oxid->value));
3965  if ($oRs != false && $oRs->recordCount() > 0) {
3966  while (!$oRs->EOF) {
3967  $sIn .= ", " . $oDb->quote(current($oRs->fields)) . " ";
3968  $oRs->moveNext();
3969  }
3970  }
3971 
3972  $iLimit = (int) $this->getConfig()->getConfigParam('iNrofCustomerWhoArticles');
3973  $iLimit = $iLimit ? ($iLimit * 10) : 50;
3974 
3975  // building sql (optimized)
3976  $sQ = "select distinct {$sArtTable}.* from (
3977  select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
3978  ) as suborder
3979  left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
3980  left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
3981  where {$sArtTable}.oxid not in ( {$sIn} )
3982  and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and " . $this->getSqlActiveSnippet();
3983 
3984  /* non optimized, but could be used if index forcing is not supported
3985  // building sql
3986  $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
3987  select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
3988  ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
3989  and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
3990  and ".$this->getSqlActiveSnippet();
3991  */
3992 
3993  return $sQ;
3994  }
3995 
4005  protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
4006  {
4007  $sCategoryView = getViewName('oxcategories');
4008  $sO2CView = getViewName('oxobject2category');
4009 
4010  $oDb = oxDb::getDb();
4011  $sOXID = $oDb->quote($sOXID);
4012  $sCatId = $oDb->quote($sCatId);
4013 
4014  if (!$dPriceFromTo) {
4015  $sSelect = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
4016  $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
4017  $sSelect .= "where oxobject2category.oxcatnid=$sCatId and oxobject2category.oxobjectid=$sOXID ";
4018  $sSelect .= "and oxcategories.oxactive = 1 order by oxobject2category.oxtime ";
4019  } else {
4020  $dPriceFromTo = $oDb->quote($dPriceFromTo);
4021  $sSelect = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
4022  $sSelect .= "oxcategories.oxid=$sCatId and $dPriceFromTo >= oxcategories.oxpricefrom and ";
4023  $sSelect .= "$dPriceFromTo <= oxcategories.oxpriceto ";
4024  }
4025 
4026  return $sSelect;
4027  }
4028 
4034  protected function _getAmountPriceList()
4035  {
4036  if ($this->_oAmountPriceList === null) {
4037  $oAmPriceList = oxNew('oxAmountPricelist');
4038 
4039  if (!$this->skipDiscounts()) {
4040  //collecting assigned to article amount-price list
4041  $oAmPriceList->load($this);
4042 
4043  // prepare abs prices if currently having percentages
4044  $oBasePrice = $this->_getGroupPrice();
4045  foreach ($oAmPriceList as $oAmPrice) {
4046  if ($oAmPrice->oxprice2article__oxaddperc->value) {
4047  $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent($oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value), oxField::T_RAW);
4048  }
4049  }
4050 
4051  }
4052 
4053  $this->_oAmountPriceList = $oAmPriceList;
4054  }
4055 
4056  return $this->_oAmountPriceList;
4057  }
4058 
4066  protected function _isFieldEmpty($sFieldName)
4067  {
4068  $mValue = $this->$sFieldName->value;
4069 
4070  if (is_null($mValue)) {
4071  return true;
4072  }
4073 
4074  if ($mValue === '') {
4075  return true;
4076  }
4077 
4078  // certain fields with zero value treat as empty
4079  $aZeroValueFields = array('oxarticles__oxprice', 'oxarticles__oxvat', 'oxarticles__oxunitquantity');
4080 
4081  if (!$mValue && in_array($sFieldName, $aZeroValueFields)) {
4082  return true;
4083  }
4084 
4085 
4086  if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
4087  return true;
4088  }
4089 
4090  $sFieldName = strtolower($sFieldName);
4091 
4092  if ($sFieldName == 'oxarticles__oxicon' && (strpos($mValue, "nopic_ico.jpg") !== false || strpos($mValue, "nopic.jpg") !== false)) {
4093  return true;
4094  }
4095 
4096  if (strpos($mValue, "nopic.jpg") !== false && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom')) {
4097  return true;
4098  }
4099 
4100  return false;
4101  }
4102 
4110  protected function _assignParentFieldValue($sFieldName)
4111  {
4112  if (!($oParentArticle = $this->getParentArticle())) {
4113  return;
4114  }
4115 
4116  $sCopyFieldName = $this->_getFieldLongName($sFieldName);
4117 
4118  // assigning only these which parent article has
4119  if ($oParentArticle->$sCopyFieldName != null) {
4120 
4121  // only overwrite database values
4122  if (substr($sCopyFieldName, 0, 12) != 'oxarticles__') {
4123  return;
4124  }
4125 
4126  //do not copy certain fields
4127  if (in_array($sCopyFieldName, $this->_aNonCopyParentFields)) {
4128  return;
4129  }
4130 
4131  //skip picture parent value assignment in case master image is set for variant
4132  if ($this->_isFieldEmpty($sCopyFieldName) && $this->_isImageField($sCopyFieldName) && $this->_hasMasterImage(1)) {
4133  return;
4134  }
4135 
4136  //COPY THE VALUE
4137  if ($this->_isFieldEmpty($sCopyFieldName)) {
4138  $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
4139  }
4140  }
4141  }
4142 
4150  protected function _isImageField($sFieldName)
4151  {
4152  $blIsImageField = (stristr($sFieldName, '_oxthumb') || stristr($sFieldName, '_oxicon') || stristr($sFieldName, '_oxzoom') || stristr($sFieldName, '_oxpic'));
4153 
4154  return $blIsImageField;
4155  }
4156 
4160  protected function _assignParentFieldValues()
4161  {
4162  startProfile('articleAssignParentInternal');
4163  if ($this->oxarticles__oxparentid->value) {
4164  // yes, we are in fact a variant
4165  if (!$this->isAdmin() || ($this->_blLoadParentData && $this->isAdmin())) {
4166  foreach ($this->_aFieldNames as $sFieldName => $sVal) {
4167  $this->_assignParentFieldValue($sFieldName);
4168  }
4169  }
4170  }
4171  stopProfile('articleAssignParentInternal');
4172  }
4173 
4177  protected function _assignNotBuyableParent()
4178  {
4179  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') &&
4180  ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value)
4181  ) {
4182  $this->_blNotBuyableParent = true;
4183 
4184  }
4185  }
4186 
4190  protected function _assignStock()
4191  {
4192  $myConfig = $this->getConfig();
4193  // -----------------------------------
4194  // stock
4195  // -----------------------------------
4196 
4197  // #1125 A. must round (using floor()) value taken from database and cast to int
4198  if (!$myConfig->getConfigParam('blAllowUnevenAmounts') && !$this->isAdmin()) {
4199  $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
4200  }
4201  //GREEN light
4202  $this->_iStockStatus = 0;
4203 
4204  // if we have flag /*1 or*/ 4 - we show always green light
4205  if ($myConfig->getConfigParam('blUseStock') && /*$this->oxarticles__oxstockflag->value != 1 && */
4206  $this->oxarticles__oxstockflag->value != 4
4207  ) {
4208  //ORANGE light
4209  $iStock = $this->oxarticles__oxstock->value;
4210 
4211  if ($this->_blNotBuyableParent) {
4212  $iStock = $this->oxarticles__oxvarstock->value;
4213  }
4214 
4215 
4216  if ($iStock <= $myConfig->getConfigParam('sStockWarningLimit') && $iStock > 0) {
4217  $this->_iStockStatus = 1;
4218  }
4219 
4220  //RED light
4221  if ($iStock <= 0) {
4222  $this->_iStockStatus = -1;
4223  }
4224  }
4225 
4226 
4227  // stock
4228  if ($myConfig->getConfigParam('blUseStock') && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
4229  $iOnStock = $this->oxarticles__oxstock->value;
4230  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
4231  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
4232  }
4233  if ($iOnStock <= 0) {
4234  $this->setBuyableState(false);
4235  }
4236  }
4237 
4238  //exceptional handling for variant parent stock:
4239  if ($this->_blNotBuyable && $this->oxarticles__oxvarstock->value) {
4240  $this->setBuyableState(true);
4241  //but then at least setting notBuaybleParent to true
4242  $this->_blNotBuyableParent = true;
4243  }
4244 
4245  //special treatment for lists when blVariantParentBuyable config option is set to false
4246  //then we just hide "to basket" button.
4247  //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
4248  if (!$myConfig->getConfigParam('blVariantParentBuyable') && !$myConfig->getConfigParam('blLoadVariants') && $this->oxarticles__oxvarstock->value) {
4249  $this->setBuyableState(false);
4250  }
4251 
4252  //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
4253  if (!$this->_blNotBuyable && $this->_blNotBuyableParent && $this->oxarticles__oxvarcount->value == 0) {
4254  $this->setBuyableState(false);
4255  }
4256  }
4257 
4261  protected function _assignPersistentParam()
4262  {
4263  // Persistent Parameter Handling
4264  $aPersParam = oxRegistry::getSession()->getVariable('persparam');
4265  if (isset($aPersParam) && isset($aPersParam[$this->getId()])) {
4266  $this->_aPersistParam = $aPersParam[$this->getId()];
4267  }
4268  }
4269 
4273  protected function _assignDynImageDir()
4274  {
4275  $myConfig = $this->getConfig();
4276 
4277  $sThisShop = $this->oxarticles__oxshopid->value;
4278 
4279  $this->_sDynImageDir = $myConfig->getPictureUrl(null, false);
4280  $this->dabsimagedir = $myConfig->getPictureDir(false); //$sThisShop
4281  $this->nossl_dimagedir = $myConfig->getPictureUrl(null, false, false, null, $sThisShop); //$sThisShop
4282  $this->ssl_dimagedir = $myConfig->getPictureUrl(null, false, true, null, $sThisShop); //$sThisShop
4283  }
4284 
4288  protected function _assignComparisonListFlag()
4289  {
4290  // #657 add a flag if article is on comparisonlist
4291 
4292  $aItems = oxRegistry::getSession()->getVariable('aFiltcompproducts');
4293  if (isset($aItems[$this->getId()])) {
4294  $this->_blIsOnComparisonList = true;
4295  }
4296  }
4297 
4305  protected function _insert()
4306  {
4307  // set oxinsert
4308  $sNow = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
4309  $this->oxarticles__oxinsert = new oxField($sNow);
4310  if (!is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
4311  $this->oxarticles__oxsubclass = new oxField('oxarticle');
4312  }
4313 
4314  $blRes = parent::_insert();
4315 
4316 
4317  return $blRes;
4318  }
4319 
4325  protected function _update()
4326  {
4327 
4328  $this->setUpdateSeo(true);
4329  $this->_setUpdateSeoOnFieldChange('oxtitle');
4330 
4331  $this->_skipSaveFields();
4332 
4333  $myConfig = $this->getConfig();
4334 
4335 
4336  $blRes = parent::_update();
4337 
4338 
4339  return $blRes;
4340  }
4341 
4349  protected function _deleteRecords($sOXID)
4350  {
4351  $oDb = oxDb::getDb();
4352 
4353  $sOXID = $oDb->quote($sOXID);
4354 
4355  //remove other records
4356  $sDelete = 'delete from oxobject2article where oxarticlenid = ' . $sOXID . ' or oxobjectid = ' . $sOXID . ' ';
4357  $oDb->execute($sDelete);
4358 
4359  $sDelete = 'delete from oxobject2attribute where oxobjectid = ' . $sOXID . ' ';
4360  $oDb->execute($sDelete);
4361 
4362  $sDelete = 'delete from oxobject2category where oxobjectid = ' . $sOXID . ' ';
4363  $oDb->execute($sDelete);
4364 
4365  $sDelete = 'delete from oxobject2selectlist where oxobjectid = ' . $sOXID . ' ';
4366  $oDb->execute($sDelete);
4367 
4368  $sDelete = 'delete from oxprice2article where oxartid = ' . $sOXID . ' ';
4369  $oDb->execute($sDelete);
4370 
4371  $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = ' . $sOXID . ' ';
4372  $oDb->execute($sDelete);
4373 
4374  $sDelete = 'delete from oxratings where oxobjectid = ' . $sOXID . ' ';
4375  $rs = $oDb->execute($sDelete);
4376 
4377  $sDelete = 'delete from oxaccessoire2article where oxobjectid = ' . $sOXID . ' or oxarticlenid = ' . $sOXID . ' ';
4378  $oDb->execute($sDelete);
4379 
4380  //#1508C - deleting oxobject2delivery entries added
4381  $sDelete = 'delete from oxobject2delivery where oxobjectid = ' . $sOXID . ' and oxtype=\'oxarticles\' ';
4382  $oDb->execute($sDelete);
4383 
4384  $sDelete = 'delete from oxartextends where oxid = ' . $sOXID . ' ';
4385  $oDb->execute($sDelete);
4386 
4387  //delete the record
4388  foreach ($this->_getLanguageSetTables("oxartextends") as $sSetTbl) {
4389  $oDb->execute("delete from $sSetTbl where oxid = {$sOXID}");
4390  }
4391 
4392  $sDelete = 'delete from oxactions2article where oxartid = ' . $sOXID . ' ';
4393  $rs = $oDb->execute($sDelete);
4394 
4395  $sDelete = 'delete from oxobject2list where oxobjectid = ' . $sOXID . ' ';
4396  $rs = $oDb->execute($sDelete);
4397 
4398 
4399  return $rs;
4400  }
4401 
4407  protected function _deleteVariantRecords($sOXID)
4408  {
4409  if ($sOXID) {
4410  $oDb = oxDb::getDb();
4411  //collect variants to remove recursively
4412  $sQ = 'select oxid from ' . $this->getViewName() . ' where oxparentid = ' . $oDb->quote($sOXID);
4413  $rs = $oDb->select($sQ, false, false);
4414  $oArticle = oxNew("oxArticle");
4415  if ($rs != false && $rs->recordCount() > 0) {
4416  while (!$rs->EOF) {
4417  $oArticle->setId($rs->fields[0]);
4418  $oArticle->delete();
4419  $rs->moveNext();
4420  }
4421  }
4422  }
4423  }
4424 
4428  protected function _deletePics()
4429  {
4430  $myUtilsPic = oxRegistry::get("oxUtilsPic");
4431  $myConfig = $this->getConfig();
4432  $oPictureHandler = oxRegistry::get("oxPictureHandler");
4433 
4434  //deleting custom main icon
4435  $oPictureHandler->deleteMainIcon($this);
4436 
4437  //deleting custom thumbnail
4438  $oPictureHandler->deleteThumbnail($this);
4439 
4440  $sAbsDynImageDir = $myConfig->getPictureDir(false);
4441 
4442  // deleting master image and all generated images
4443  $iPicCount = $myConfig->getConfigParam('iPicCount');
4444  for ($i = 1; $i <= $iPicCount; $i++) {
4445  $oPictureHandler->deleteArticleMasterPicture($this, $i);
4446  }
4447  }
4448 
4456  protected function _onChangeResetCounts($sOxid, $sVendorId = null, $sManufacturerId = null)
4457  {
4458  $myUtilsCount = oxRegistry::get("oxUtilsCount");
4459 
4460  if ($sVendorId) {
4461  $myUtilsCount->resetVendorArticleCount($sVendorId);
4462  }
4463 
4464  if ($sManufacturerId) {
4465  $myUtilsCount->resetManufacturerArticleCount($sManufacturerId);
4466  }
4467 
4468  $aCategoryIds = $this->getCategoryIds();
4469  //also reseting category counts
4470  foreach ($aCategoryIds as $sCatId) {
4471  $myUtilsCount->resetCatArticleCount($sCatId, false);
4472  }
4473  }
4474 
4480  protected function _onChangeUpdateStock($sParentID)
4481  {
4482  if ($sParentID) {
4483  $oDb = oxDb::getDb();
4484  $sParentIdQuoted = $oDb->quote($sParentID);
4485  $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = ' . $sParentIdQuoted;
4486  $rs = $oDb->select($sQ, false, false);
4487  $iOldStock = $rs->fields[0];
4488  $iVendorID = $rs->fields[1];
4489  $iManufacturerID = $rs->fields[2];
4490 
4491  $sQ = 'select sum(oxstock) from ' . $this->getViewName(true) . ' where oxparentid = ' . $sParentIdQuoted . ' and ' . $this->getSqlActiveSnippet(true) . ' and oxstock > 0 ';
4492  $iStock = (float) $oDb->getOne($sQ, false, false);
4493 
4494  $sQ = 'update oxarticles set oxvarstock = ' . $iStock . ' where oxid = ' . $sParentIdQuoted;
4495  $oDb->execute($sQ);
4496 
4497  //now lets update category counts
4498  //first detect stock status change for this article (to or from 0)
4499  if ($iStock < 0) {
4500  $iStock = 0;
4501  }
4502  if ($iOldStock < 0) {
4503  $iOldStock = 0;
4504  }
4505  if ($this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock) {
4506  //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
4507  // so far we leave it like this but later we could move all count resets to one or two functions
4508  $this->_onChangeResetCounts($sParentID, $iVendorID, $iManufacturerID);
4509  }
4510  }
4511  }
4512 
4518  protected function _onChangeStockResetCount($sOxid)
4519  {
4520  $myConfig = $this->getConfig();
4521 
4522  if ($myConfig->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2 &&
4523  ($this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value) <= 0
4524  ) {
4525 
4526  $this->_onChangeResetCounts($sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
4527  }
4528  }
4529 
4535  protected function _onChangeUpdateVarCount($sParentID)
4536  {
4537  if ($sParentID) {
4538  $oDb = oxDb::getDb();
4539  $sParentIdQuoted = $oDb->quote($sParentID);
4540  $sQ = "select count(*) as varcount from oxarticles where oxparentid = {$sParentIdQuoted}";
4541  $iVarCount = (int) $oDb->getOne($sQ, false, false);
4542 
4543  $sQ = "update oxarticles set oxvarcount = {$iVarCount} where oxid = {$sParentIdQuoted}";
4544  $oDb->execute($sQ);
4545  }
4546  }
4547 
4553  protected function _setVarMinMaxPrice($sParentId)
4554  {
4555  if ($sParentId) {
4557  $sQ = '
4558  SELECT
4559  MIN( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varminprice`,
4560  MAX( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varmaxprice`
4561  FROM ' . $this->getViewName(true) . ' AS `oxarticles`
4562  LEFT JOIN ' . $this->getViewName(true) . ' AS `p` ON ( `p`.`oxid` = `oxarticles`.`oxparentid` AND `p`.`oxprice` > 0 )
4563  WHERE ' . $this->getSqlActiveSnippet(true) . '
4564  AND ( `oxarticles`.`oxparentid` = ' . $oDb->quote($sParentId) . ' )';
4565  $oDb->setFetchMode(oxDb::FETCH_MODE_ASSOC);
4566  $aPrices = $oDb->getRow($sQ, false, false);
4567  if (!is_null($aPrices['varminprice']) || !is_null($aPrices['varmaxprice'])) {
4568  $sQ = '
4569  UPDATE `oxarticles`
4570  SET
4571  `oxvarminprice` = ' . $oDb->quote($aPrices['varminprice']) . ',
4572  `oxvarmaxprice` = ' . $oDb->quote($aPrices['varmaxprice']) . '
4573  WHERE
4574  `oxid` = ' . $oDb->quote($sParentId);
4575  } else {
4576  $sQ = '
4577  UPDATE `oxarticles`
4578  SET
4579  `oxvarminprice` = `oxprice`,
4580  `oxvarmaxprice` = `oxprice`
4581  WHERE
4582  `oxid` = ' . $oDb->quote($sParentId);
4583  }
4584  $oDb->execute($sQ);
4585  }
4586  }
4587 
4595  protected function _hasMasterImage($iIndex)
4596  {
4597  $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
4598 
4599  if ($sPicName == "nopic.jpg" || $sPicName == "") {
4600  return false;
4601  }
4602  if ($this->isVariant() &&
4603  $this->getParentArticle() &&
4604  $this->getParentArticle()->{"oxarticles__oxpic" . $iIndex}->value == $this->{"oxarticles__oxpic" . $iIndex}->value
4605  ) {
4606  return false;
4607  }
4608 
4609  $sMasterPic = 'product/' . $iIndex . "/" . $sPicName;
4610 
4611  if ($this->getConfig()->getMasterPicturePath($sMasterPic)) {
4612  return true;
4613  }
4614 
4615  return false;
4616  }
4617 
4623  protected function _isPriceViewModeNetto()
4624  {
4625  $blResult = (bool) $this->getConfig()->getConfigParam('blShowNetPrice');
4626  $oUser = $this->getArticleUser();
4627  if ($oUser) {
4628  $blResult = $oUser->isPriceViewModeNetto();
4629  }
4630 
4631  return $blResult;
4632  }
4633 
4634 
4642  protected function _getPriceObject($blCalculationModeNetto = null)
4643  {
4644  $oPrice = oxNew('oxPrice');
4645 
4646  if ($blCalculationModeNetto === null) {
4647  $blCalculationModeNetto = $this->_isPriceViewModeNetto();
4648  }
4649 
4650  if ($blCalculationModeNetto) {
4651  $oPrice->setNettoPriceMode();
4652  } else {
4653  $oPrice->setBruttoPriceMode();
4654  }
4655 
4656  return $oPrice;
4657  }
4658 
4659 
4667  protected function _getPriceForView($oPrice)
4668  {
4669  if ($this->_isPriceViewModeNetto()) {
4670  $dPrice = $oPrice->getNettoPrice();
4671  } else {
4672  $dPrice = $oPrice->getBruttoPrice();
4673  }
4674 
4675  return $dPrice;
4676  }
4677 
4678 
4688  protected function _preparePrice($dPrice, $dVat, $blCalculationModeNetto = null)
4689  {
4690  if ($blCalculationModeNetto === null) {
4691  $blCalculationModeNetto = $this->_isPriceViewModeNetto();
4692  }
4693 
4694  $oCurrency = $this->getConfig()->getActShopCurrencyObject();
4695 
4696  $blEnterNetPrice = $this->getConfig()->getConfigParam('blEnterNetPrice');
4697  if ($blCalculationModeNetto && !$blEnterNetPrice) {
4698  $dPrice = round(oxPrice::brutto2Netto($dPrice, $dVat), $oCurrency->decimal);
4699  } elseif (!$blCalculationModeNetto && $blEnterNetPrice) {
4700  $dPrice = round(oxPrice::netto2Brutto($dPrice, $dVat), $oCurrency->decimal);
4701  }
4702 
4703  return $dPrice;
4704  }
4705 
4711  protected function _getUserPriceSufix()
4712  {
4713  $sPriceSuffix = '';
4714  $oUser = $this->getArticleUser();
4715 
4716  if ($oUser) {
4717  if ($oUser->inGroup('oxidpricea')) {
4718  $sPriceSuffix = 'a';
4719  } elseif ($oUser->inGroup('oxidpriceb')) {
4720  $sPriceSuffix = 'b';
4721  } elseif ($oUser->inGroup('oxidpricec')) {
4722  $sPriceSuffix = 'c';
4723  }
4724  }
4725 
4726  return $sPriceSuffix;
4727  }
4728 
4729 
4735  protected function _getPrice()
4736  {
4737  $sPriceSuffix = $this->_getUserPriceSufix();
4738  if ($sPriceSuffix === '') {
4739  $dPrice = $this->oxarticles__oxprice->value;
4740  } else {
4741  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4742  $dPrice = ($this->{oxarticles__oxprice . $sPriceSuffix}->value != 0) ? $this->{oxarticles__oxprice . $sPriceSuffix}->value : $this->oxarticles__oxprice->value;
4743  } else {
4744  $dPrice = $this->{oxarticles__oxprice . $sPriceSuffix}->value;
4745  }
4746  }
4747 
4748  return $dPrice;
4749  }
4750 
4751 
4757  protected function _getVarMinPrice()
4758  {
4759  if ($this->_dVarMinPrice === null) {
4760  $dPrice = null;
4761 
4762 
4763  if (is_null($dPrice)) {
4764  $sPriceSuffix = $this->_getUserPriceSufix();
4765  if ($sPriceSuffix === '') {
4766  $dPrice = $this->oxarticles__oxvarminprice->value;
4767  } else {
4768  $sSql = 'SELECT ';
4769  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4770  $sSql .= 'MIN( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varminprice` ';
4771  } else {
4772  $sSql .= 'MIN(`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
4773  }
4774 
4775  $sSql .= ' FROM ' . $this->getViewName(true) . '
4776  WHERE ' . $this->getSqlActiveSnippet(true) . '
4777  AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
4778 
4779  $dPrice = oxDb::getDb()->getOne($sSql);
4780  }
4781  }
4782 
4783  $this->_dVarMinPrice = $dPrice;
4784  }
4785 
4786  return $this->_dVarMinPrice;
4787  }
4788 
4794  protected function _getSubShopVarMinPrice()
4795  {
4796  $myConfig = $this->getConfig();
4797  $sShopId = $myConfig->getShopId();
4798  if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
4799  $sPriceSuffix = $this->_getUserPriceSufix();
4800  $sSql = 'SELECT ';
4801  if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4802  $sSql .= 'MIN(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varminprice` ';
4803  } else {
4804  $sSql .= 'MIN(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
4805  }
4806  $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
4807  INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
4808  WHERE ' . $this->getSqlActiveSnippet(true) . '
4809  AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
4810  AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
4811  $dPrice = oxDb::getDb()->getOne($sSql);
4812  }
4813 
4814  return $dPrice;
4815  }
4816 
4822  protected function _getVarMaxPrice()
4823  {
4824  if ($this->_dVarMaxPrice === null) {
4825 
4826  $dPrice = null;
4827 
4828  if (is_null($dPrice)) {
4829  $sPriceSuffix = $this->_getUserPriceSufix();
4830  if ($sPriceSuffix === '') {
4831  $dPrice = $this->oxarticles__oxvarmaxprice->value;
4832  } else {
4833  $sSql = 'SELECT ';
4834  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4835  $sSql .= 'MAX( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varmaxprice` ';
4836  } else {
4837  $sSql .= 'MAX(`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
4838  }
4839 
4840  $sSql .= ' FROM ' . $this->getViewName(true) . '
4841  WHERE ' . $this->getSqlActiveSnippet(true) . '
4842  AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
4843 
4844  $dPrice = oxDb::getDb()->getOne($sSql);
4845  }
4846  }
4847 
4848  $this->_dVarMaxPrice = $dPrice;
4849  }
4850 
4851  return $this->_dVarMaxPrice;
4852  }
4853 
4859  protected function _getSubShopVarMaxPrice()
4860  {
4861  $myConfig = $this->getConfig();
4862  $sShopId = $myConfig->getShopId();
4863  if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
4864  $sPriceSuffix = $this->_getUserPriceSufix();
4865  $sSql = 'SELECT ';
4866  if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4867  $sSql .= 'MAX(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varmaxprice` ';
4868  } else {
4869  $sSql .= 'MAX(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
4870  }
4871  $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
4872  INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
4873  WHERE ' . $this->getSqlActiveSnippet(true) . '
4874  AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
4875  AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
4876  $dPrice = oxDb::getDb()->getOne($sSql);
4877  }
4878 
4879  return $dPrice;
4880  }
4881 
4889  protected function _loadFromDb($sOXID)
4890  {
4891 
4892  $sSelect = $this->buildSelectString(array($this->getViewName() . ".oxid" => $sOXID));
4893 
4894 
4895  $aData = oxDb::getDb(oxDb::FETCH_MODE_ASSOC)->getRow($sSelect);
4896 
4897  return $aData;
4898  }
4899 
4905  protected function _updateParentDependFields()
4906  {
4907  $oDb = oxDb::getDb();
4908 
4909  foreach ($this->_getCopyParentFields() as $sField) {
4910  $sValue = isset($this->$sField->value) ? $this->$sField->value : 0;
4911  $sSqlSets[] = '`' . str_replace('oxarticles__', '', $sField) . '` = ' . $oDb->quote($sValue);
4912  }
4913 
4914  $sSql = "UPDATE `oxarticles` SET ";
4915  $sSql .= implode(', ', $sSqlSets) . '';
4916  $sSql .= " WHERE `oxparentid` = " . $oDb->quote($this->getId());
4917 
4918  return $oDb->execute($sSql);
4919  }
4920 
4921 
4927  protected function _getCopyParentFields()
4928  {
4929  return $this->_aCopyParentField;
4930  }
4931 
4935  protected function _assignParentDependFields()
4936  {
4937  $sParent = $this->getParentArticle();
4938  if ($sParent) {
4939  foreach ($this->_getCopyParentFields() as $sField) {
4940  $this->$sField = new oxField($sParent->$sField->value);
4941  }
4942  }
4943  }
4944 
4945 
4946 
4950  protected function _saveSortingFieldValuesOnLoad()
4951  {
4952  $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
4953  $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
4954 
4955  foreach ($aSortingFields as $sField) {
4956  $sFullField = $this->_getFieldLongName($sField);
4957  $this->_aSortingFieldsOnLoad[$sFullField] = $this->$sFullField->value;
4958  }
4959  }
4960 }