OXID eShop CE  4.9.7
 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  $sArticleTable = $this->getViewName();
1259 
1260  $sAttribs = '';
1261  $iCnt = 0;
1262  $this->_getAttribsString($sAttribs, $iCnt);
1263 
1264  if (!$sAttribs) {
1265  return null;
1266  }
1267 
1268  $aList = $this->_getSimList($sAttribs, $iCnt);
1269 
1270  if (count($aList)) {
1271  uasort($aList, 'cmpart');
1272 
1273  $sSearch = $this->_generateSimListSearchStr($sArticleTable, $aList);
1274 
1275  $oSimilarlist = oxNew('oxarticlelist');
1276  $oSimilarlist->setSqlLimit(0, $myConfig->getConfigParam('iNrofSimilarArticles'));
1277  $oSimilarlist->selectString($sSearch);
1278 
1279  return $oSimilarlist;
1280  }
1281  }
1282 
1289  {
1290  // Performance
1291  $myConfig = $this->getConfig();
1292  if (!$myConfig->getConfigParam('bl_perfLoadCustomerWhoBoughtThis')) {
1293  return;
1294  }
1295 
1296  // selecting products that fits
1297  $sQ = $this->_generateSearchStrForCustomerBought();
1298 
1299  $oArticles = oxNew('oxarticlelist');
1300  $oArticles->setSqlLimit(0, $myConfig->getConfigParam('iNrofCustomerWhoArticles'));
1301  $oArticles->selectString($sQ);
1302  if ($oArticles->count()) {
1303  return $oArticles;
1304  }
1305  }
1306 
1313  public function loadAmountPriceInfo()
1314  {
1315  $myConfig = $this->getConfig();
1316  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice || !$this->_blCalcPrice || !$this->hasAmountPrice()) {
1317  return array();
1318  }
1319 
1320  if ($this->_oAmountPriceInfo === null) {
1321  $this->_oAmountPriceInfo = array();
1322  if (count(($aAmPriceList = $this->_getAmountPriceList()->getArray()))) {
1323  $this->_oAmountPriceInfo = $this->_fillAmountPriceList($aAmPriceList);
1324  }
1325  }
1326 
1327  return $this->_oAmountPriceInfo;
1328  }
1329 
1337  public function getSelectLists($sKeyPrefix = null)
1338  {
1339  //#1468C - more then one article in basket with different selectlist...
1340  //optionall function parameter $sKeyPrefix added, used only in basket.php
1341  $sKey = $this->getId();
1342  if (isset($sKeyPrefix)) {
1343  $sKey = $sKeyPrefix . '__' . $sKey;
1344  }
1345 
1346  if (!isset(self::$_aSelList[$sKey])) {
1347  $oDb = oxDb::getDb();
1348  $sSLViewName = getViewName('oxselectlist');
1349 
1350  $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
1351  where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
1352 
1353  // all selectlists this article has
1354  $oLists = oxNew('oxlist');
1355  $oLists->init('oxselectlist');
1356  $oLists->selectString(sprintf($sQ, $oDb->quote($this->getId())));
1357 
1358  //#1104S if this is variant ant it has no selectlists, trying with parent
1359  if ($oLists->count() == 0 && $this->oxarticles__oxparentid->value) {
1360  $oLists->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
1361  }
1362 
1363  // We do not need to calculate price here as there are method to get current article vat
1364  /*if ( $this->getPrice() != null ) {
1365  $dVat = $this->getPrice()->getVat();
1366  }*/
1367  $dVat = $this->getArticleVat();
1368 
1369  $iCnt = 0;
1370  self::$_aSelList[$sKey] = array();
1371  foreach ($oLists as $oSelectlist) {
1372  self::$_aSelList[$sKey][$iCnt] = $oSelectlist->getFieldList($dVat);
1373  self::$_aSelList[$sKey][$iCnt]['name'] = $oSelectlist->oxselectlist__oxtitle->value;
1374  $iCnt++;
1375  }
1376  }
1377 
1378  return self::$_aSelList[$sKey];
1379  }
1380 
1386  public function getVariantsCount()
1387  {
1388  return $this->oxarticles__oxvarcount->value;
1389  }
1390 
1396  public function hasMdVariants()
1397  {
1398  return $this->_blHasMdVariants;
1399  }
1400 
1406  public function hasIntangibleAgreement()
1407  {
1408  return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxnonmaterial->value && !$this->hasDownloadableAgreement();
1409  }
1410 
1416  public function hasDownloadableAgreement()
1417  {
1418  return $this->oxarticles__oxshowcustomagreement->value && $this->oxarticles__oxisdownloadable->value;
1419  }
1420 
1430  public function getVariantSelections($aFilterIds = null, $sActVariantId = null, $iLimit = 0)
1431  {
1432  $iLimit = (int) $iLimit;
1433  if (!isset($this->_aVariantSelections[$iLimit])) {
1434  $aVariantSelections = false;
1435  if ($this->oxarticles__oxvarcount->value) {
1436  $oVariants = $this->getVariants(false);
1437  $aVariantSelections = oxNew("oxVariantHandler")->buildVariantSelections($this->oxarticles__oxvarname->getRawValue(), $oVariants, $aFilterIds, $sActVariantId, $iLimit);
1438 
1439  if (!empty($oVariants) && empty($aVariantSelections['rawselections'])) {
1440  $aVariantSelections = false;
1441  }
1442  }
1443  $this->_aVariantSelections[$iLimit] = $aVariantSelections;
1444  }
1445 
1446  return $this->_aVariantSelections[$iLimit];
1447  }
1448 
1457  public function getSelections($iLimit = null, $aFilter = null)
1458  {
1459  $sId = $this->getId() . ((int) $iLimit);
1460  if (!array_key_exists($sId, self::$_aSelections)) {
1461 
1462  $oDb = oxDb::getDb();
1463  $sSLViewName = getViewName('oxselectlist');
1464 
1465  $sQ = "select {$sSLViewName}.* from oxobject2selectlist join {$sSLViewName} on $sSLViewName.oxid=oxobject2selectlist.oxselnid
1466  where oxobject2selectlist.oxobjectid=%s order by oxobject2selectlist.oxsort";
1467 
1468  if (($iLimit = (int) $iLimit)) {
1469  $sQ .= " limit $iLimit ";
1470  }
1471 
1472  // vat value for price
1473  $dVat = 0;
1474  if (($oPrice = $this->getPrice()) != null) {
1475  $dVat = $oPrice->getVat();
1476  }
1477 
1478  // all selectlists this article has
1479  $oList = oxNew('oxlist');
1480  $oList->init('oxselectlist');
1481  $oList->getBaseObject()->setVat($dVat);
1482  $oList->selectString(sprintf($sQ, $oDb->quote($this->getId())));
1483 
1484  //#1104S if this is variant and it has no selectlists, trying with parent
1485  if ($oList->count() == 0 && $this->oxarticles__oxparentid->value) {
1486  $oList->selectString(sprintf($sQ, $oDb->quote($this->oxarticles__oxparentid->value)));
1487  }
1488 
1489  self::$_aSelections[$sId] = $oList->count() ? $oList : false;
1490  }
1491 
1492  if (self::$_aSelections[$sId]) {
1493  // marking active from filter
1494  $aFilter = ($aFilter === null) ? oxRegistry::getConfig()->getRequestParameter("sel") : $aFilter;
1495  if ($aFilter) {
1496  $iSelIdx = 0;
1497  foreach (self::$_aSelections[$sId] as $oSelection) {
1498  if (isset($aFilter[$iSelIdx])) {
1499  $oSelection->setActiveSelectionByIndex($aFilter[$iSelIdx]);
1500  }
1501  $iSelIdx++;
1502  }
1503  }
1504  }
1505 
1506  return self::$_aSelections[$sId];
1507  }
1508 
1517  public function getFullVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
1518  {
1519  return $this->_loadVariantList(false, $blRemoveNotOrderables, $blForceCoreTable);
1520  }
1521 
1531  public function getVariants($blRemoveNotOrderables = true, $blForceCoreTable = null)
1532  {
1533  return $this->_loadVariantList($this->_isInList(), $blRemoveNotOrderables, $blForceCoreTable);
1534  }
1535 
1541  public function getSimpleVariants()
1542  {
1543  if ($this->oxarticles__oxvarcount->value) {
1544  return $this->getVariants();
1545  }
1546  }
1547 
1556  public function getAdminVariants($sLanguage = null)
1557  {
1558  $oVariants = oxNew('oxarticlelist');
1559  if (($sId = $this->getId())) {
1560 
1561  $oBaseObj = $oVariants->getBaseObject();
1562 
1563  if (is_null($sLanguage)) {
1564  $oBaseObj->setLanguage(oxRegistry::getLang()->getBaseLanguage());
1565  } else {
1566  $oBaseObj->setLanguage($sLanguage);
1567  }
1568 
1569  $sSql = "select * from " . $oBaseObj->getViewName() . " where oxparentid = '{$sId}' order by oxsort ";
1570  $oVariants->selectString($sSql);
1571 
1572  //if we have variants then depending on config option the parent may be non buyable
1573  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && ($oVariants->count() > 0)) {
1574  //$this->blNotBuyable = true;
1575  $this->_blNotBuyableParent = true;
1576  }
1577  }
1578 
1579  return $oVariants;
1580  }
1581 
1589  public function getCategory()
1590  {
1591  $oCategory = oxNew('oxcategory');
1592  $oCategory->setLanguage($this->getLanguage());
1593 
1594  // variant handling
1595  $sOXID = $this->getId();
1596  if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
1597  $sOXID = $this->oxarticles__oxparentid->value;
1598  }
1599 
1600  if ($sOXID) {
1601  // if the oxcategory instance of this article is not cached
1602  if (!isset($this->_aCategoryCache[$sOXID])) {
1603  startPRofile('getCategory');
1604  $oStr = getStr();
1605  $sWhere = $oCategory->getSqlActiveSnippet();
1606  $sSelect = $this->_generateSearchStr($sOXID);
1607  $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " order by oxobject2category.oxtime limit 1";
1608 
1609  // category not found ?
1610  if (!$oCategory->assignRecord($sSelect)) {
1611 
1612  $sSelect = $this->_generateSearchStr($sOXID, true);
1613  $sSelect .= ($oStr->strstr($sSelect, 'where') ? ' and ' : ' where ') . $sWhere . " limit 1";
1614 
1615  // looking for price category
1616  if (!$oCategory->assignRecord($sSelect)) {
1617  $oCategory = null;
1618  }
1619  }
1620  // add the category instance to cache
1621  $this->_aCategoryCache[$sOXID] = $oCategory;
1622  stopPRofile('getCategory');
1623  } else {
1624  // if the oxcategory instance is cached
1625  $oCategory = $this->_aCategoryCache[$sOXID];
1626  }
1627  }
1628 
1629  return $oCategory;
1630  }
1631 
1640  public function getCategoryIds($blActCats = false, $blSkipCache = false)
1641  {
1642  $sArticleId = $this->getId();
1643 
1644  if (!isset(self::$_aArticleCats[$sArticleId]) || $blSkipCache) {
1645 
1646  $sSql = $this->_getCategoryIdsSelect($blActCats);
1647  $aCategoryIds = $this->_selectCategoryIds($sSql, 'oxcatnid');
1648 
1649  $sSql = $this->getSqlForPriceCategories();
1650  $aPriceCategoryIds = $this->_selectCategoryIds($sSql, 'oxid');
1651 
1652  self::$_aArticleCats[$sArticleId] = array_unique(array_merge($aCategoryIds, $aPriceCategoryIds));
1653  }
1654 
1655  return self::$_aArticleCats[$sArticleId];
1656  }
1657 
1667  public function getVendor($blShopCheck = true)
1668  {
1669  if (($sVendorId = $this->getVendorId())) {
1670  $oVendor = oxNew('oxvendor');
1671  } elseif (!$blShopCheck && $this->oxarticles__oxvendorid->value) {
1672  $oVendor = oxNew('oxi18n');
1673  $oVendor->init('oxvendor');
1674  $oVendor->setReadOnly(true);
1675  $sVendorId = $this->oxarticles__oxvendorid->value;
1676  }
1677  if ($sVendorId && $oVendor->load($sVendorId) && $oVendor->oxvendor__oxactive->value) {
1678 
1679  return $oVendor;
1680  }
1681 
1682  return null;
1683  }
1684 
1692  public function getVendorId($blForceReload = false)
1693  {
1694  $sVendorId = false;
1695  if ($this->oxarticles__oxvendorid->value) {
1696  $sVendorId = $this->oxarticles__oxvendorid->value;
1697 
1698  }
1699 
1700  return $sVendorId;
1701  }
1702 
1710  public function getManufacturerId($blForceReload = false)
1711  {
1712  $sManufacturerId = false;
1713  if ($this->oxarticles__oxmanufacturerid->value) {
1714 
1715  $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
1716 
1717  }
1718 
1719  return $sManufacturerId;
1720  }
1721 
1731  public function getManufacturer($blShopCheck = true)
1732  {
1733  $oManufacturer = oxNew('oxmanufacturer');
1734  if (!($sManufacturerId = $this->getManufacturerId()) &&
1735  !$blShopCheck && $this->oxarticles__oxmanufacturerid->value
1736  ) {
1737  $oManufacturer->setReadOnly(true);
1738  $sManufacturerId = $this->oxarticles__oxmanufacturerid->value;
1739  }
1740 
1741  if ($sManufacturerId && $oManufacturer->load($sManufacturerId)) {
1742  if (!$this->getConfig()->getConfigParam('bl_perfLoadManufacturerTree')) {
1743  $oManufacturer->setReadOnly(true);
1744  }
1745  $oManufacturer = $oManufacturer->oxmanufacturers__oxactive->value ? $oManufacturer : null;
1746  } else {
1747  $oManufacturer = null;
1748  }
1749 
1750  return $oManufacturer;
1751  }
1752 
1760  public function inCategory($sCatNid)
1761  {
1762  return in_array($sCatNid, $this->getCategoryIds());
1763  }
1764 
1773  public function isAssignedToCategory($sCatId)
1774  {
1775  // variant handling
1776  $sOXID = $this->getId();
1777  if (isset($this->oxarticles__oxparentid->value) && $this->oxarticles__oxparentid->value) {
1778  $sOXID = $this->oxarticles__oxparentid->value;
1779  }
1780 
1781  $oDb = oxDb::getDb();
1782  $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId);
1783  $sOXID = $oDb->getOne($sSelect);
1784  // article is assigned to passed category!
1785  if (isset($sOXID) && $sOXID) {
1786  return true;
1787  }
1788 
1789  // maybe this category is price category ?
1790  if ($this->getConfig()->getConfigParam('bl_perfLoadPrice') && $this->_blLoadPrice) {
1791  $dPriceFromTo = $this->getPrice()->getBruttoPrice();
1792  if ($dPriceFromTo > 0) {
1793  $sSelect = $this->_generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo);
1794  $sOXID = $oDb->getOne($sSelect);
1795  // article is assigned to passed category!
1796  if (isset($sOXID) && $sOXID) {
1797  return true;
1798  }
1799  }
1800  }
1801 
1802  return false;
1803  }
1804 
1810  public function getTPrice()
1811  {
1812  if (!$this->getConfig()->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1813  return;
1814  }
1815 
1816  // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
1817  if ($this->_oTPrice !== null) {
1818  return $this->_oTPrice;
1819  }
1820 
1821  $oPrice = $this->_getPriceObject();
1822 
1823  $dBasePrice = $this->oxarticles__oxtprice->value;
1824  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
1825 
1826  $oPrice->setPrice($dBasePrice);
1827 
1828  $this->_applyVat($oPrice, $this->getArticleVat());
1829  $this->_applyCurrency($oPrice);
1830 
1831  if ($this->isParentNotBuyable()) {
1832  // if parent article is not buyable then compare agains min article variant price
1833  $oPrice2 = $this->getVarMinPrice();
1834  } else {
1835  // else compare against article price
1836  $oPrice2 = $this->getPrice();
1837  }
1838 
1839  if ($oPrice->getPrice() <= $oPrice2->getPrice()) {
1840  // if RRP price is less or equal to comparable price then return
1841  return;
1842  }
1843 
1844  $this->_oTPrice = $oPrice;
1845 
1846  return $this->_oTPrice;
1847  }
1848 
1854  public function skipDiscounts()
1855  {
1856  // already loaded skip discounts config
1857  if ($this->_blSkipDiscounts !== null) {
1858  return $this->_blSkipDiscounts;
1859  }
1860 
1861  if ($this->oxarticles__oxskipdiscounts->value) {
1862  return true;
1863  }
1864 
1865 
1866  $this->_blSkipDiscounts = false;
1867  if (oxRegistry::get("oxDiscountList")->hasSkipDiscountCategories()) {
1868 
1869  $oDb = oxDb::getDb();
1870  $sO2CView = getViewName('oxobject2category', $this->getLanguage());
1871  $sViewName = getViewName('oxcategories', $this->getLanguage());
1872  $sSelect = "select 1 from $sO2CView as $sO2CView left join {$sViewName} on {$sViewName}.oxid = $sO2CView.oxcatnid
1873  where $sO2CView.oxobjectid=" . $oDb->quote($this->getId()) . " and {$sViewName}.oxactive = 1 and {$sViewName}.oxskipdiscounts = '1' ";
1874  $this->_blSkipDiscounts = ($oDb->getOne($sSelect) == 1);
1875  }
1876 
1877  return $this->_blSkipDiscounts;
1878  }
1879 
1885  public function setPrice(oxPrice $oPrice)
1886  {
1887  $this->_oPrice = $oPrice;
1888  }
1889 
1898  public function getBasePrice($dAmount = 1)
1899  {
1900  // override this function if you want e.g. different prices
1901  // for diff. user groups.
1902 
1903  // Performance
1904  $myConfig = $this->getConfig();
1905  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1906  return;
1907  }
1908 
1909  // GroupPrice or DB price ajusted by AmountPrice
1910  $dPrice = $this->_getAmountPrice($dAmount);
1911 
1912 
1913  return $dPrice;
1914  }
1915 
1923  public function getPrice($dAmount = 1)
1924  {
1925  $myConfig = $this->getConfig();
1926  // Performance
1927  if (!$myConfig->getConfigParam('bl_perfLoadPrice') || !$this->_blLoadPrice) {
1928  return;
1929  }
1930 
1931  // return cached result, since oPrice is created ONLY in this function [or function of EQUAL level]
1932  if ($dAmount != 1 || $this->_oPrice === null) {
1933 
1934  // module
1935  $dBasePrice = $this->getBasePrice($dAmount);
1936  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
1937 
1938  $oPrice = $this->_getPriceObject();
1939 
1940  $oPrice->setPrice($dBasePrice);
1941 
1942  // price handling
1943  if (!$this->_blCalcPrice && $dAmount == 1) {
1944  return $this->_oPrice = $oPrice;
1945  }
1946 
1947  $this->_calculatePrice($oPrice);
1948  if ($dAmount != 1) {
1949  return $oPrice;
1950  }
1951 
1952  $this->_oPrice = $oPrice;
1953  }
1954 
1955  return $this->_oPrice;
1956  }
1957 
1963  public function setArticleUser($oUser)
1964  {
1965  $this->_oUser = $oUser;
1966  }
1967 
1973  public function getArticleUser()
1974  {
1975  if ($this->_oUser) {
1976  return $this->_oUser;
1977  }
1978 
1979  return $this->getUser();
1980  }
1981 
1991  public function getBasketPrice($dAmount, $aSelList, $oBasket)
1992  {
1993  $oUser = $oBasket->getBasketUser();
1994  $this->setArticleUser($oUser);
1995 
1996  $oBasketPrice = $this->_getPriceObject($oBasket->isCalculationModeNetto());
1997 
1998  // get base price
1999  $dBasePrice = $this->getBasePrice($dAmount);
2000 
2001  $dBasePrice = $this->_modifySelectListPrice($dBasePrice, $aSelList);
2002  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat(), $oBasket->isCalculationModeNetto());
2003 
2004  // applying select list price
2005 
2006  // setting price
2007  $oBasketPrice->setPrice($dBasePrice);
2008 
2009  $dVat = oxRegistry::get("oxVatSelector")->getBasketItemVat($this, $oBasket);
2010  $this->_calculatePrice($oBasketPrice, $dVat);
2011 
2012  // returning final price object
2013  return $oBasketPrice;
2014  }
2015 
2024  public function delete($sOXID = null)
2025  {
2026  if (!$sOXID) {
2027  $sOXID = $this->getId();
2028  }
2029  if (!$sOXID) {
2030  return false;
2031  }
2032 
2033 
2034 
2035  // #2339 delete first variants before deleting parent product
2036  $this->_deleteVariantRecords($sOXID);
2037  $this->load($sOXID);
2038  $this->_deletePics();
2039  $this->_onChangeResetCounts($sOXID, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
2040 
2041  // delete self
2042  parent::delete($sOXID);
2043 
2044  $rs = $this->_deleteRecords($sOXID);
2045 
2046  oxRegistry::get("oxSeoEncoderArticle")->onDeleteArticle($this);
2047 
2048  $this->onChange(ACTION_DELETE, $sOXID, $this->oxarticles__oxparentid->value);
2049 
2050  return $rs->EOF;
2051  }
2052 
2061  public function reduceStock($dAmount, $blAllowNegativeStock = false)
2062  {
2063  $this->beforeUpdate();
2064 
2065  $iStockCount = $this->oxarticles__oxstock->value - $dAmount;
2066  if (!$blAllowNegativeStock && ($iStockCount < 0)) {
2067  $dAmount += $iStockCount;
2068  $iStockCount = 0;
2069  }
2070  $this->oxarticles__oxstock = new oxField($iStockCount);
2071 
2072  $oDb = oxDb::getDb();
2073  $oDb->execute('update oxarticles set oxarticles.oxstock = ' . $oDb->quote($iStockCount) . ' where oxarticles.oxid = ' . $oDb->quote($this->getId()));
2074  $this->onChange(ACTION_UPDATE_STOCK);
2075 
2076  return $dAmount;
2077  }
2078 
2087  public function updateSoldAmount($dAmount = 0)
2088  {
2089  if (!$dAmount) {
2090  return;
2091  }
2092 
2093  // article is not variant - should be updated current amount
2094  if (!$this->oxarticles__oxparentid->value) {
2095  //updating by SQL query, due to wrong behaviour if saving article using not admin mode
2096  $dAmount = (double) $dAmount;
2097  $oDb = oxDb::getDb();
2098  $rs = $oDb->execute("update oxarticles set oxarticles.oxsoldamount = oxarticles.oxsoldamount + $dAmount where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
2099  } elseif ($this->oxarticles__oxparentid->value) {
2100  // article is variant - should be updated this article parent amount
2101  $oUpdateArticle = $this->getParentArticle();
2102  if ($oUpdateArticle) {
2103  $oUpdateArticle->updateSoldAmount($dAmount);
2104  }
2105  }
2106 
2107  return $rs;
2108  }
2109 
2115  public function disableReminder()
2116  {
2117  $oDb = oxDb::getDb();
2118 
2119  return $oDb->execute("update oxarticles set oxarticles.oxremindactive = 2 where oxarticles.oxid = " . $oDb->quote($this->oxarticles__oxid->value));
2120  }
2121 
2127  public function save()
2128  {
2129  $this->_assignParentDependFields();
2130 
2131  if (($blRet = parent::save())) {
2132  // saving long description
2133  $this->_saveArtLongDesc();
2134  }
2135 
2136  return $blRet;
2137  }
2138 
2142  public function resetParent()
2143  {
2144  $sParentId = $this->oxarticles__oxparentid->value;
2145  $this->oxarticles__oxparentid = new oxField('', oxField::T_RAW);
2146  $this->_blAllowEmptyParentId = true;
2147  $this->save();
2148  $this->_blAllowEmptyParentId = false;
2149 
2150  if ($sParentId !== '') {
2151  $this->onChange(ACTION_UPDATE, null, $sParentId);
2152  }
2153  }
2154 
2155 
2162  public function getPictureGallery()
2163  {
2164  $myConfig = $this->getConfig();
2165 
2166  //initialize
2167  $blMorePic = false;
2168  $aArtPics = array();
2169  $aArtIcons = array();
2170  $iActPicId = 1;
2171  $sActPic = $this->getPictureUrl($iActPicId);
2172 
2173  if (oxRegistry::getConfig()->getRequestParameter('actpicid')) {
2174  $iActPicId = oxRegistry::getConfig()->getRequestParameter('actpicid');
2175  }
2176 
2177  $oStr = getStr();
2178  $iCntr = 0;
2179  $iPicCount = $myConfig->getConfigParam('iPicCount');
2180  $blCheckActivePicId = true;
2181 
2182  for ($i = 1; $i <= $iPicCount; $i++) {
2183  $sPicVal = $this->getPictureUrl($i);
2184  $sIcoVal = $this->getIconUrl($i);
2185  if (!$oStr->strstr($sIcoVal, 'nopic_ico.jpg') && !$oStr->strstr($sIcoVal, 'nopic.jpg') &&
2186  !$oStr->strstr($sPicVal, 'nopic_ico.jpg') && !$oStr->strstr($sPicVal, 'nopic.jpg')
2187  ) {
2188  if ($iCntr) {
2189  $blMorePic = true;
2190  }
2191  $aArtIcons[$i] = $sIcoVal;
2192  $aArtPics[$i] = $sPicVal;
2193  $iCntr++;
2194 
2195  if ($iActPicId == $i) {
2196  $sActPic = $sPicVal;
2197  $blCheckActivePicId = false;
2198  }
2199 
2200  } elseif ($blCheckActivePicId && $iActPicId <= $i) {
2201  // if picture is empty, setting active pic id to next
2202  // picture
2203  $iActPicId++;
2204  }
2205  }
2206 
2207  $blZoomPic = false;
2208  $aZoomPics = array();
2209  $iZoomPicCount = $myConfig->getConfigParam('iPicCount');
2210 
2211  for ($j = 1, $c = 1; $j <= $iZoomPicCount; $j++) {
2212  $sVal = $this->getZoomPictureUrl($j);
2213 
2214  if ($sVal && !$oStr->strstr($sVal, 'nopic.jpg')) {
2215  $blZoomPic = true;
2216  $aZoomPics[$c]['id'] = $c;
2217  $aZoomPics[$c]['file'] = $sVal;
2218  //anything is better than empty name, because <img src=""> calls shop once more = x2 SLOW.
2219  if (!$sVal) {
2220  $aZoomPics[$c]['file'] = "nopic.jpg";
2221  }
2222  $c++;
2223  }
2224  }
2225 
2226  $aPicGallery = array('ActPicID' => $iActPicId,
2227  'ActPic' => $sActPic,
2228  'MorePics' => $blMorePic,
2229  'Pics' => $aArtPics,
2230  'Icons' => $aArtIcons,
2231  'ZoomPic' => $blZoomPic,
2232  'ZoomPics' => $aZoomPics);
2233 
2234  return $aPicGallery;
2235  }
2236 
2250  public function onChange($sAction = null, $sOXID = null, $sParentID = null)
2251  {
2252  $myConfig = $this->getConfig();
2253 
2254  if (!isset($sOXID)) {
2255  if ($this->getId()) {
2256  $sOXID = $this->getId();
2257  }
2258  if (!isset ($sOXID)) {
2259  $sOXID = $this->oxarticles__oxid->value;
2260  }
2261  if ($this->oxarticles__oxparentid->value) {
2262  $sParentID = $this->oxarticles__oxparentid->value;
2263  }
2264  }
2265  if (!isset($sOXID)) {
2266  return;
2267  }
2268 
2269  //if (isset($sOXID) && !$myConfig->blVariantParentBuyable && $myConfig->blUseStock)
2270  if ($myConfig->getConfigParam('blUseStock')) {
2271  //if article has variants then updating oxvarstock field
2272  //getting parent id
2273  if (!isset($sParentID)) {
2274  $oDb = oxDb::getDb();
2275  $sQ = 'select oxparentid from oxarticles where oxid = ' . $oDb->quote($sOXID);
2276  $sParentID = $oDb->getOne($sQ);
2277  }
2278  //if we have parent id then update stock
2279  if ($sParentID) {
2280  $this->_onChangeUpdateStock($sParentID);
2281  }
2282  }
2283  //if we have parent id then update count
2284  //update count even if blUseStock is not active
2285  if ($sParentID) {
2286  $this->_onChangeUpdateVarCount($sParentID);
2287  }
2288 
2289  $sId = ($sParentID) ? $sParentID : $sOXID;
2290  $this->_setVarMinMaxPrice($sId);
2291 
2292  $this->_updateParentDependFields();
2293 
2294  // resetting articles count cache if stock has changed and some
2295  // articles goes offline (M:1448)
2296  if ($sAction === ACTION_UPDATE_STOCK) {
2297  $this->_assignStock();
2298  $this->_onChangeStockResetCount($sOXID);
2299  }
2300 
2301  }
2302 
2309  public function getCustomVAT()
2310  {
2311  if (isset($this->oxarticles__oxvat->value)) {
2312  return $this->oxarticles__oxvat->value;
2313  }
2314  }
2315 
2324  public function checkForStock($dAmount, $dArtStockAmount = 0)
2325  {
2326  $myConfig = $this->getConfig();
2327  if (!$myConfig->getConfigParam('blUseStock')) {
2328  return true;
2329  }
2330 
2332  // fetching DB info as its up-to-date
2333  $sQ = 'select oxstock, oxstockflag from oxarticles where oxid = ' . $oDb->quote($this->getId());
2334  $rs = $oDb->select($sQ);
2335 
2336  $iOnStock = 0;
2337  $iStockFlag = 0;
2338  if ($rs !== false && $rs->recordCount() > 0) {
2339  $iOnStock = $rs->fields['oxstock'] - $dArtStockAmount;
2340  $iStockFlag = $rs->fields['oxstockflag'];
2341 
2342  // foreign stock is also always considered as on stock
2343  if ($iStockFlag == 1 || $iStockFlag == 4) {
2344  return true;
2345  }
2346  if (!$myConfig->getConfigParam('blAllowUnevenAmounts')) {
2347  $iOnStock = floor($iOnStock);
2348  }
2349  }
2350  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
2351  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
2352  }
2353  if ($iOnStock >= $dAmount) {
2354  return true;
2355  } else {
2356  if ($iOnStock > 0) {
2357  return $iOnStock;
2358  } else {
2359  $oEx = oxNew('oxArticleInputException');
2360  $oEx->setMessage('ERROR_MESSAGE_ARTICLE_ARTICLE_NOT_BUYABLE');
2361  oxRegistry::get("oxUtilsView")->addErrorToDisplay($oEx);
2362 
2363  return false;
2364  }
2365  }
2366  }
2367 
2368 
2374  public function getLongDescription()
2375  {
2376  if ($this->_oLongDesc === null) {
2377  // initializing
2378  $this->_oLongDesc = new oxField();
2379 
2380 
2381  // choosing which to get..
2382  $sOxid = $this->getId();
2383  $sViewName = getViewName('oxartextends', $this->getLanguage());
2384 
2385  $oDb = oxDb::getDb();
2386  $sDbValue = $oDb->getOne("select oxlongdesc from {$sViewName} where oxid = " . $oDb->quote($sOxid));
2387 
2388  if ($sDbValue != false) {
2389  $this->_oLongDesc->setValue($sDbValue, oxField::T_RAW);
2390  } elseif ($this->oxarticles__oxparentid->value) {
2391  if (!$this->isAdmin() || $this->_blLoadParentData) {
2392  $oParent = $this->getParentArticle();
2393  if ($oParent) {
2394  $this->_oLongDesc->setValue($oParent->getLongDescription()->getRawValue(), oxField::T_RAW);
2395  }
2396  }
2397  }
2398  }
2399 
2400  return $this->_oLongDesc;
2401  }
2402 
2409  public function getLongDesc()
2410  {
2411  return oxRegistry::get("oxUtilsView")->parseThroughSmarty($this->getLongDescription()->getRawValue(), $this->getId() . $this->getLanguage(), null, true);
2412  }
2413 
2421  public function setArticleLongDesc($sDesc)
2422  {
2423 
2424  // setting current value
2425  $this->_oLongDesc = new oxField($sDesc, oxField::T_RAW);
2426  $this->oxarticles__oxlongdesc = new oxField($sDesc, oxField::T_RAW);
2427  }
2428 
2434  public function getAttributes()
2435  {
2436  if ($this->_oAttributeList === null) {
2437  $this->_oAttributeList = oxNew('oxattributelist');
2438  $this->_oAttributeList->loadAttributes($this->getId(), $this->getParentId());
2439  }
2440 
2441  return $this->_oAttributeList;
2442  }
2443 
2450  {
2451  if ($this->_oAttributeList === null) {
2452  $this->_oAttributeList = oxNew('oxattributelist');
2453  $this->_oAttributeList->loadAttributesDisplayableInBasket($this->getId(), $this->getParentId());
2454  }
2455 
2456  return $this->_oAttributeList;
2457  }
2458 
2459 
2466  public function appendLink($sAddParams, $iLang = null)
2467  {
2468  if ($sAddParams) {
2469  if ($iLang === null) {
2470  $iLang = $this->getLanguage();
2471  }
2472 
2473  $this->_aSeoAddParams[$iLang] = isset($this->_aSeoAddParams[$iLang]) ? $this->_aSeoAddParams[$iLang] . "&amp;" : "";
2474  $this->_aSeoAddParams[$iLang] .= $sAddParams;
2475  }
2476  }
2477 
2486  public function getBaseSeoLink($iLang, $blMain = false)
2487  {
2489  $oEncoder = oxRegistry::get("oxSeoEncoderArticle");
2490  if (!$blMain) {
2491  return $oEncoder->getArticleUrl($this, $iLang, $this->getLinkType());
2492  }
2493 
2494  return $oEncoder->getArticleMainUrl($this, $iLang);
2495  }
2496 
2505  public function getLink($iLang = null, $blMain = false)
2506  {
2507  if (!oxRegistry::getUtils()->seoIsActive()) {
2508  return $this->getStdLink($iLang);
2509  }
2510 
2511  if ($iLang === null) {
2512  $iLang = $this->getLanguage();
2513  }
2514 
2515  $iLinkType = $this->getLinkType();
2516  if (!isset($this->_aSeoUrls[$iLang][$iLinkType])) {
2517  $this->_aSeoUrls[$iLang][$iLinkType] = $this->getBaseSeoLink($iLang, $blMain);
2518  }
2519 
2520  $sUrl = $this->_aSeoUrls[$iLang][$iLinkType];
2521  if (isset($this->_aSeoAddParams[$iLang])) {
2522  $sUrl .= ((strpos($sUrl . $this->_aSeoAddParams[$iLang], '?') === false) ? '?' : '&amp;') . $this->_aSeoAddParams[$iLang];
2523  }
2524 
2525  return $sUrl;
2526  }
2527 
2536  public function getMainLink($iLang = null)
2537  {
2538  return $this->getLink($iLang, true);
2539  }
2540 
2546  public function setLinkType($iType)
2547  {
2548  // resetting details link, to force new
2549  $this->_sDetailLink = null;
2550 
2551  // setting link type
2552  $this->_iLinkType = (int) $iType;
2553  }
2554 
2560  public function getLinkType()
2561  {
2562  return $this->_iLinkType;
2563  }
2564 
2571  public function appendStdLink($sAddParams, $iLang = null)
2572  {
2573  if ($sAddParams) {
2574  if ($iLang === null) {
2575  $iLang = $this->getLanguage();
2576  }
2577 
2578  $this->_aStdAddParams[$iLang] = isset($this->_aStdAddParams[$iLang]) ? $this->_aStdAddParams[$iLang] . "&amp;" : "";
2579  $this->_aStdAddParams[$iLang] .= $sAddParams;
2580  }
2581  }
2582 
2592  public function getBaseStdLink($iLang, $blAddId = true, $blFull = true)
2593  {
2594  $sUrl = '';
2595  if ($blFull) {
2596  //always returns shop url, not admin
2597  $sUrl = $this->getConfig()->getShopUrl($iLang, false);
2598  }
2599 
2600  $sUrl .= "index.php?cl=details" . ($blAddId ? "&amp;anid=" . $this->getId() : "");
2601 
2602  return $sUrl . (isset($this->_aStdAddParams[$iLang]) ? "&amp;" . $this->_aStdAddParams[$iLang] : "");
2603  }
2604 
2613  public function getStdLink($iLang = null, $aParams = array())
2614  {
2615  if ($iLang === null) {
2616  $iLang = $this->getLanguage();
2617  }
2618 
2619  if (!isset($this->_aStdUrls[$iLang])) {
2620  $this->_aStdUrls[$iLang] = $this->getBaseStdLink($iLang);
2621  }
2622 
2623  return oxRegistry::get("oxUtilsUrl")->processUrl($this->_aStdUrls[$iLang], true, $aParams, $iLang);
2624  }
2625 
2631  public function getMediaUrls()
2632  {
2633  if ($this->_aMediaUrls === null) {
2634  $this->_aMediaUrls = oxNew("oxlist");
2635  $this->_aMediaUrls->init("oxmediaurl");
2636  $this->_aMediaUrls->getBaseObject()->setLanguage($this->getLanguage());
2637 
2638  $sViewName = getViewName("oxmediaurls", $this->getLanguage());
2639  $sQ = "select * from {$sViewName} where oxobjectid = '" . $this->getId() . "'";
2640  $this->_aMediaUrls->selectString($sQ);
2641  }
2642 
2643  return $this->_aMediaUrls;
2644  }
2645 
2651  public function getDynImageDir()
2652  {
2653  return $this->_sDynImageDir;
2654  }
2655 
2661  public function getDispSelList()
2662  {
2663  if ($this->_aDispSelList === null) {
2664  if ($this->getConfig()->getConfigParam('bl_perfLoadSelectLists') && $this->getConfig()->getConfigParam('bl_perfLoadSelectListsInAList')) {
2665  $this->_aDispSelList = $this->getSelectLists();
2666  }
2667  }
2668 
2669  return $this->_aDispSelList;
2670  }
2671 
2677  public function getMoreDetailLink()
2678  {
2679  if ($this->_sMoreDetailLink == null) {
2680 
2681  // and assign special article values
2682  $this->_sMoreDetailLink = $this->getConfig()->getShopHomeURL() . 'cl=moredetails';
2683 
2684  // not always it is okey, as not all the time active category is the same as primary article cat.
2685  if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
2686  $this->_sMoreDetailLink .= '&amp;cnid=' . $sActCat;
2687  }
2688  $this->_sMoreDetailLink .= '&amp;anid=' . $this->getId();
2689  $this->_sMoreDetailLink = $this->_sMoreDetailLink;
2690  }
2691 
2692  return $this->_sMoreDetailLink;
2693  }
2694 
2700  public function getToBasketLink()
2701  {
2702  if ($this->_sToBasketLink == null) {
2703  $myConfig = $this->getConfig();
2704 
2705  if (oxRegistry::getUtils()->isSearchEngine()) {
2706  $this->_sToBasketLink = $this->getLink();
2707  } else {
2708  // and assign special article values
2709  $this->_sToBasketLink = $myConfig->getShopHomeURL();
2710 
2711  // override some classes as these should never showup
2712  $sActClass = oxRegistry::getConfig()->getRequestParameter('cl');
2713  if ($sActClass == 'thankyou') {
2714  $sActClass = 'basket';
2715  }
2716  $this->_sToBasketLink .= 'cl=' . $sActClass;
2717 
2718  // this is not very correct
2719  if ($sActCat = oxRegistry::getConfig()->getRequestParameter('cnid')) {
2720  $this->_sToBasketLink .= '&amp;cnid=' . $sActCat;
2721  }
2722 
2723  $this->_sToBasketLink .= '&amp;fnc=tobasket&amp;aid=' . $this->getId() . '&amp;anid=' . $this->getId();
2724 
2725  if ($sTpl = basename(oxRegistry::getConfig()->getRequestParameter('tpl'))) {
2726  $this->_sToBasketLink .= '&amp;tpl=' . $sTpl;
2727  }
2728  }
2729  }
2730 
2731  return $this->_sToBasketLink;
2732  }
2733 
2739  public function getStockStatus()
2740  {
2741  return $this->_iStockStatus;
2742  }
2743 
2749  public function getDeliveryDate()
2750  {
2751  if ($this->oxarticles__oxdelivery->value != '0000-00-00') {
2752  return oxRegistry::get("oxUtilsDate")->formatDBDate($this->oxarticles__oxdelivery->value);
2753  }
2754 
2755  return false;
2756  }
2757 
2765  public function getFTPrice()
2766  {
2767  // module
2768  if ($oPrice = $this->getTPrice()) {
2769  if ($dPrice = $this->_getPriceForView($oPrice)) {
2770  return oxRegistry::getLang()->formatCurrency($dPrice);
2771  }
2772  }
2773  }
2774 
2782  public function getFPrice()
2783  {
2784  if ($oPrice = $this->getPrice()) {
2785  $dPrice = $this->_getPriceForView($oPrice);
2786 
2787  return oxRegistry::getLang()->formatCurrency($dPrice);
2788  }
2789  }
2790 
2795  public function resetRemindStatus()
2796  {
2797  if ($this->oxarticles__oxremindactive->value == 2 &&
2798  $this->oxarticles__oxremindamount->value <= $this->oxarticles__oxstock->value
2799  ) {
2800  $this->oxarticles__oxremindactive->value = 1;
2801  }
2802  }
2803 
2811  public function getFNetPrice()
2812  {
2813  if ($oPrice = $this->getPrice()) {
2814  return oxRegistry::getLang()->formatCurrency($oPrice->getNettoPrice());
2815  }
2816  }
2817 
2823  public function isParentNotBuyable()
2824  {
2826  }
2827 
2833  public function isNotBuyable()
2834  {
2835  return $this->_blNotBuyable;
2836  }
2837 
2843  public function setBuyableState($blBuyable = false)
2844  {
2845  $this->_blNotBuyable = !$blBuyable;
2846  }
2847 
2853  public function setSelectlist($aSelList)
2854  {
2855  $this->_aDispSelList = $aSelList;
2856  }
2857 
2865  public function getPictureUrl($iIndex = 1)
2866  {
2867  if ($iIndex) {
2868  $sImgName = false;
2869  if (!$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
2870  $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
2871  }
2872 
2873  $sSize = $this->getConfig()->getConfigParam('aDetailImageSizes');
2874 
2875  return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
2876  }
2877  }
2878 
2887  public function getIconUrl($iIndex = 0)
2888  {
2889  $sImgName = false;
2890  $sDirname = "product/1/";
2891  if ($iIndex && !$this->_isFieldEmpty("oxarticles__oxpic{$iIndex}")) {
2892  $sImgName = basename($this->{"oxarticles__oxpic$iIndex"}->value);
2893  $sDirname = "product/{$iIndex}/";
2894  } elseif (!$this->_isFieldEmpty("oxarticles__oxicon")) {
2895  $sImgName = basename($this->oxarticles__oxicon->value);
2896  $sDirname = "product/icon/";
2897  } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
2898  $sImgName = basename($this->oxarticles__oxpic1->value);
2899  }
2900 
2901  $sSize = $this->getConfig()->getConfigParam('sIconsize');
2902 
2903  $sIconUrl = oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, $iIndex);
2904 
2905  return $sIconUrl;
2906  }
2907 
2915  public function getThumbnailUrl($bSsl = null)
2916  {
2917  $sImgName = false;
2918  $sDirname = "product/1/";
2919  if (!$this->_isFieldEmpty("oxarticles__oxthumb")) {
2920  $sImgName = basename($this->oxarticles__oxthumb->value);
2921  $sDirname = "product/thumb/";
2922  } elseif (!$this->_isFieldEmpty("oxarticles__oxpic1")) {
2923  $sImgName = basename($this->oxarticles__oxpic1->value);
2924  }
2925 
2926  $sSize = $this->getConfig()->getConfigParam('sThumbnailsize');
2927 
2928  return oxRegistry::get("oxPictureHandler")->getProductPicUrl($sDirname, $sImgName, $sSize, 0, $bSsl);
2929  }
2930 
2938  public function getZoomPictureUrl($iIndex = '')
2939  {
2940  $iIndex = (int) $iIndex;
2941  if ($iIndex > 0 && !$this->_isFieldEmpty("oxarticles__oxpic" . $iIndex)) {
2942  $sImgName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
2943  $sSize = $this->getConfig()->getConfigParam("sZoomImageSize");
2944 
2945  return oxRegistry::get("oxPictureHandler")->getProductPicUrl("product/{$iIndex}/", $sImgName, $sSize, 'oxpic' . $iIndex);
2946  }
2947  }
2948 
2954  public function applyVats(oxPrice $oPrice)
2955  {
2956  $this->_applyVAT($oPrice, $this->getArticleVat());
2957  }
2958 
2964  public function applyDiscountsForVariant($oPrice)
2965  {
2966  // apply discounts
2967  if (!$this->skipDiscounts()) {
2968  $oDiscountList = oxRegistry::get("oxDiscountList");
2969  $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
2970 
2971  reset($aDiscounts);
2972  foreach ($aDiscounts as $oDiscount) {
2973  $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
2974  }
2975  $oPrice->calculateDiscount();
2976  }
2977  }
2978 
2984  public function getParentArticle()
2985  {
2986  if (($sParentId = $this->oxarticles__oxparentid->value)) {
2987  $sIndex = $sParentId . "_" . $this->getLanguage();
2988  if (!isset(self::$_aLoadedParents[$sIndex])) {
2989  self::$_aLoadedParents[$sIndex] = oxNew('oxarticle');
2990  self::$_aLoadedParents[$sIndex]->_blLoadPrice = false;
2991  self::$_aLoadedParents[$sIndex]->_blLoadVariants = false;
2992 
2993  if (!self::$_aLoadedParents[$sIndex]->loadInLang($this->getLanguage(), $sParentId)) {
2994  //return false in case parent product failed to load
2995  self::$_aLoadedParents[$sIndex] = false;
2996  }
2997  }
2998 
2999  return self::$_aLoadedParents[$sIndex];
3000  }
3001  }
3002 
3006  public function updateVariantsRemind()
3007  {
3008  // check if it is parent article
3009  if (!$this->isVariant() && $this->_hasAnyVariant()) {
3010  $oDb = oxDb::getDb();
3011  $sOxId = $oDb->quote($this->getId());
3012  $sOxShopId = $oDb->quote($this->getShopId());
3013  $iRemindActive = $oDb->quote($this->oxarticles__oxremindactive->value);
3014  $sUpdate = "
3015  update oxarticles
3016  set oxremindactive = $iRemindActive
3017  where oxparentid = $sOxId and
3018  oxshopid = $sOxShopId
3019  ";
3020  $oDb->execute($sUpdate);
3021  }
3022  }
3023 
3030  public function getProductId()
3031  {
3032  return $this->getId();
3033  }
3034 
3040  public function getParentId()
3041  {
3042  return $this->oxarticles__oxparentid->value;
3043  }
3044 
3050  public function isOrderArticle()
3051  {
3052  return false;
3053  }
3054 
3060  public function isVariant()
3061  {
3062  return (bool) (isset($this->oxarticles__oxparentid) ? $this->oxarticles__oxparentid->value : false);
3063  }
3064 
3070  public function isMdVariant()
3071  {
3072  $oMdVariant = oxNew("oxVariantHandler");
3073 
3074  return $oMdVariant->isMdVariant($this);
3075  }
3076 
3084  public function getSqlForPriceCategories($sFields = '')
3085  {
3086  if (!$sFields) {
3087  $sFields = 'oxid';
3088  }
3089  $sSelectWhere = "select $sFields from " . $this->_getObjectViewName('oxcategories') . " where";
3090  $sQuotedPrice = oxDb::getDb()->quote($this->oxarticles__oxprice->value);
3091 
3092  return "$sSelectWhere oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice"
3093  . " union $sSelectWhere oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice"
3094  . " union $sSelectWhere oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice";
3095  }
3096 
3104  public function inPriceCategory($sCatNid)
3105  {
3106  $oDb = oxDb::getDb();
3107 
3108  $sQuotedPrice = $oDb->quote($this->oxarticles__oxprice->value);
3109  $sQuotedCnid = $oDb->quote($sCatNid);
3110 
3111  return (bool) $oDb->getOne(
3112  "select 1 from " . $this->_getObjectViewName('oxcategories') . " where oxid=$sQuotedCnid and"
3113  . "( (oxpricefrom != 0 and oxpriceto != 0 and oxpricefrom <= $sQuotedPrice and oxpriceto >= $sQuotedPrice)"
3114  . " or (oxpricefrom != 0 and oxpriceto = 0 and oxpricefrom <= $sQuotedPrice)"
3115  . " or (oxpricefrom = 0 and oxpriceto != 0 and oxpriceto >= $sQuotedPrice)"
3116  . ")"
3117  );
3118  }
3119 
3125  public function getMdVariants()
3126  {
3127  if ($this->_oMdVariants) {
3128  return $this->_oMdVariants;
3129  }
3130 
3131  $oParentArticle = $this->getParentArticle();
3132  if ($oParentArticle) {
3133  $oVariants = $oParentArticle->getVariants();
3134  } else {
3135  $oVariants = $this->getVariants();
3136  }
3137 
3138  $oVariantHandler = oxNew("oxVariantHandler");
3139  $this->_oMdVariants = $oVariantHandler->buildMdVariants($oVariants, $this->getId());
3140 
3141  return $this->_oMdVariants;
3142  }
3143 
3149  public function getMdSubvariants()
3150  {
3151  return $this->getMdVariants()->getMdSubvariants();
3152  }
3153 
3162  public function getPictureFieldValue($sFieldName, $iIndex = null)
3163  {
3164  if ($sFieldName) {
3165  $sFieldName = "oxarticles__" . $sFieldName . $iIndex;
3166 
3167  return $this->$sFieldName->value;
3168  }
3169  }
3170 
3178  public function getMasterZoomPictureUrl($iIndex)
3179  {
3180  $sPicUrl = false;
3181  $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
3182 
3183  if ($sPicName && $sPicName != "nopic.jpg") {
3184  $sPicUrl = $this->getConfig()->getPictureUrl("master/product/" . $iIndex . "/" . $sPicName);
3185  if (!$sPicUrl || basename($sPicUrl) == "nopic.jpg") {
3186  $sPicUrl = false;
3187  }
3188  }
3189 
3190  return $sPicUrl;
3191  }
3192 
3198  public function getUnitName()
3199  {
3200  if ($this->oxarticles__oxunitname->value) {
3201  return oxRegistry::getLang()->translateString($this->oxarticles__oxunitname->value);
3202  }
3203  }
3204 
3212  public function getArticleFiles($blAddFromParent = false)
3213  {
3214  if ($this->_aArticleFiles === null) {
3215 
3216  $this->_aArticleFiles = false;
3217 
3218  $sQ = "SELECT * FROM `oxfiles` WHERE `oxartid` = '" . $this->getId() . "'";
3219 
3220  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') && $blAddFromParent) {
3221  $sQ .= " OR `oxartId` = '" . $this->oxarticles__oxparentid->value . "'";
3222  }
3223 
3224  $oArticleFiles = oxNew("oxlist");
3225  $oArticleFiles->init("oxfile");
3226  $oArticleFiles->selectString($sQ);
3227  $this->_aArticleFiles = $oArticleFiles;
3228 
3229  }
3230 
3231  return $this->_aArticleFiles;
3232  }
3233 
3239  public function isDownloadable()
3240  {
3241  return $this->oxarticles__oxisdownloadable->value;
3242  }
3243 
3249  public function hasAmountPrice()
3250  {
3251  if (self::$_blHasAmountPrice === null) {
3252 
3253  self::$_blHasAmountPrice = false;
3254 
3255  $oDb = oxDb::getDb();
3256  $sQ = "SELECT 1 FROM `oxprice2article` LIMIT 1";
3257 
3258  if ($oDb->getOne($sQ)) {
3259  self::$_blHasAmountPrice = true;
3260  }
3261  }
3262 
3263  return self::$_blHasAmountPrice;
3264  }
3265 
3275  protected function _loadVariantList($blSimple, $blRemoveNotOrderables = true, $blForceCoreTable = null)
3276  {
3277  $oVariants = array();
3278  if (($sId = $this->getId())) {
3279  //do not load me as a parent later
3280  self::$_aLoadedParents[$sId . "_" . $this->getLanguage()] = $this;
3281 
3282  $myConfig = $this->getConfig();
3283 
3284  if (!$this->_blLoadVariants ||
3285  (!$this->isAdmin() && !$myConfig->getConfigParam('blLoadVariants')) ||
3286  (!$this->isAdmin() && !$this->oxarticles__oxvarcount->value)
3287  ) {
3288  return $oVariants;
3289  }
3290 
3291  // cache
3292  $sCacheKey = $blSimple ? "simple" : "full";
3293  if ($blRemoveNotOrderables) {
3294  if (isset($this->_aVariants[$sCacheKey])) {
3295  return $this->_aVariants[$sCacheKey];
3296  } else {
3297  $this->_aVariants[$sCacheKey] = & $oVariants;
3298  }
3299  } elseif (!$blRemoveNotOrderables) {
3300  if (isset($this->_aVariantsWithNotOrderables[$sCacheKey])) {
3301  return $this->_aVariantsWithNotOrderables[$sCacheKey];
3302  } else {
3303  $this->_aVariantsWithNotOrderables[$sCacheKey] = & $oVariants;
3304  }
3305  }
3306 
3307  if (($this->_blHasVariants = $this->_hasAnyVariant($blForceCoreTable))) {
3308 
3309  //load simple variants for lists
3310  if ($blSimple) {
3311  $oVariants = oxNew('oxsimplevariantlist');
3312  $oVariants->setParent($this);
3313  } else {
3314  //loading variants
3315  $oVariants = oxNew('oxarticlelist');
3316  $oVariants->getBaseObject()->modifyCacheKey('_variants');
3317  }
3318 
3319  startProfile("selectVariants");
3320  $blUseCoreTable = (bool) $blForceCoreTable;
3321  $oBaseObject = $oVariants->getBaseObject();
3322  $oBaseObject->setLanguage($this->getLanguage());
3323 
3324 
3325  $sArticleTable = $this->getViewName($blUseCoreTable);
3326 
3327  $sSelect = "select " . $oBaseObject->getSelectFields($blUseCoreTable) . " from $sArticleTable where " .
3328  $this->getActiveCheckQuery($blUseCoreTable) .
3329  $this->getVariantsQuery($blRemoveNotOrderables, $blUseCoreTable) .
3330  " order by $sArticleTable.oxsort";
3331  $oVariants->selectString($sSelect);
3332 
3333  //if this is multidimensional variants, make additional processing
3334  if ($myConfig->getConfigParam('blUseMultidimensionVariants')) {
3335  $oMdVariants = oxNew("oxVariantHandler");
3336  $this->_blHasMdVariants = $oMdVariants->isMdVariant($oVariants->current());
3337  }
3338  stopProfile("selectVariants");
3339  }
3340 
3341  //if we have variants then depending on config option the parent may be non buyable
3342  if (!$myConfig->getConfigParam('blVariantParentBuyable') && $this->_blHasVariants) {
3343  $this->_blNotBuyableParent = true;
3344  }
3345 
3346  //if we have variants, but all variants are incative means article may be non buyable (depends on config option)
3347  if (!$myConfig->getConfigParam('blVariantParentBuyable') && count($oVariants) == 0 && $this->_blHasVariants) {
3348  $this->_blNotBuyable = true;
3349  }
3350  }
3351 
3352  return $oVariants;
3353  }
3354 
3363  protected function _selectCategoryIds($sSql, $sField)
3364  {
3366  $aResult = $oDb->getAll($sSql);
3367  $aReturn = array();
3368 
3369 
3370  foreach ($aResult as $aValue) {
3371  $aValue = array_change_key_case($aValue, CASE_LOWER);
3372 
3373 
3374  $aReturn[] = $aValue[$sField];
3375  }
3376 
3377  return $aReturn;
3378  }
3379 
3387  protected function _getCategoryIdsSelect($blActCats = false)
3388  {
3389  $sO2CView = $this->_getObjectViewName('oxobject2category');
3390  $sCatView = $this->_getObjectViewName('oxcategories');
3391 
3392  $sArticleIdSql = 'oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getId());
3393  if ($this->getParentId()) {
3394  $sArticleIdSql = '(' . $sArticleIdSql . ' or oxobject2category.oxobjectid=' . oxDb::getDb()->quote($this->getParentId()) . ')';
3395  }
3396  $sActiveCategorySql = $blActCats ? $this->_getActiveCategorySelectSnippet() : '';
3397 
3398  $sSelect = "select
3399  oxobject2category.oxcatnid as oxcatnid
3400  from $sO2CView as oxobject2category
3401  left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid
3402  where $sArticleIdSql and oxcategories.oxid is not null and oxcategories.oxactive = 1 $sActiveCategorySql
3403  order by oxobject2category.oxtime";
3404 
3405  return $sSelect;
3406  }
3407 
3413  protected function _getActiveCategorySelectSnippet()
3414  {
3415  $sCatView = $this->_getObjectViewName('oxcategories');
3416  $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 ";
3417 
3418  return $sActiveCategorySql;
3419  }
3420 
3431  protected function _getSelectCatIds($sOXID, $blActCats = false)
3432  {
3433  $sO2CView = $this->_getObjectViewName('oxobject2category');
3434  $sCatView = $this->_getObjectViewName('oxcategories');
3435  $sSelect = "select oxobject2category.oxcatnid as oxcatnid from $sO2CView as oxobject2category left join $sCatView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
3436  $sSelect .= 'where oxobject2category.oxobjectid=' . oxDb::getDb()->quote($sOXID) . ' and oxcategories.oxid is not null and oxcategories.oxactive = 1 ';
3437  if ($blActCats) {
3438  $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 ";
3439  }
3440  $sSelect .= 'order by oxobject2category.oxtime ';
3441 
3442  return $sSelect;
3443  }
3444 
3453  protected function _calculatePrice($oPrice, $dVat = null)
3454  {
3455  // apply VAT only if configuration requires it
3456  if (isset($dVat) || !$this->getConfig()->getConfigParam('bl_perfCalcVatOnlyForBasketOrder')) {
3457  $this->_applyVAT($oPrice, isset($dVat) ? $dVat : $this->getArticleVat());
3458  }
3459 
3460  // apply currency
3461  $this->_applyCurrency($oPrice);
3462  // apply discounts
3463  if (!$this->skipDiscounts()) {
3464  $oDiscountList = oxRegistry::get("oxDiscountList");
3465  $aDiscounts = $oDiscountList->getArticleDiscounts($this, $this->getArticleUser());
3466 
3467  reset($aDiscounts);
3468  foreach ($aDiscounts as $oDiscount) {
3469  $oPrice->setDiscount($oDiscount->getAddSum(), $oDiscount->getAddSumType());
3470  }
3471  $oPrice->calculateDiscount();
3472  }
3473 
3474  return $oPrice;
3475  }
3476 
3484  protected function _hasAnyVariant($blForceCoreTable = null)
3485  {
3486  $blHas = false;
3487  if (($sId = $this->getId())) {
3488  if ($this->oxarticles__oxshopid->value == $this->getConfig()->getShopId()) {
3489  $blHas = (bool) $this->oxarticles__oxvarcount->value;
3490  } else {
3491  $sArticleTable = $this->getViewName($blForceCoreTable);
3492  $blHas = (bool) oxDb::getDb()->getOne("select 1 from $sArticleTable where oxparentid='{$sId}'");
3493  }
3494  }
3495 
3496  return $blHas;
3497  }
3498 
3504  protected function _isStockStatusChanged()
3505  {
3506  return $this->_iStockStatus != $this->_iStockStatusOnLoad;
3507  }
3508 
3514  protected function _isVisibilityChanged()
3515  {
3516  return $this->_isStockStatusChanged() && ($this->_iStockStatus == -1 || $this->_iStockStatusOnLoad == -1);
3517  }
3518 
3524  protected function _saveArtLongDesc()
3525  {
3526  $myConfig = $this->getConfig();
3527  $sShopId = $myConfig->getShopID();
3528  if (in_array("oxlongdesc", $this->_aSkipSaveFields)) {
3529  return;
3530  }
3531 
3532  if ($this->_blEmployMultilanguage) {
3533  $sValue = $this->getLongDescription()->getRawValue();
3534  if ($sValue !== null) {
3535  $oArtExt = oxNew('oxI18n');
3536  $oArtExt->init('oxartextends');
3537  $oArtExt->setLanguage((int) $this->getLanguage());
3538  if (!$oArtExt->load($this->getId())) {
3539  $oArtExt->setId($this->getId());
3540  }
3541  $oArtExt->oxartextends__oxlongdesc = new oxField($sValue, oxField::T_RAW);
3542  $oArtExt->save();
3543  }
3544  } else {
3545  $oArtExt = oxNew('oxI18n');
3546  $oArtExt->setEnableMultilang(false);
3547  $oArtExt->init('oxartextends');
3548  $aObjFields = $oArtExt->_getAllFields(true);
3549  if (!$oArtExt->load($this->getId())) {
3550  $oArtExt->setId($this->getId());
3551  }
3552 
3553  foreach ($aObjFields as $sKey => $sValue) {
3554  if (preg_match('/^oxlongdesc(_(\d{1,2}))?$/', $sKey)) {
3555  $sField = $this->_getFieldLongName($sKey);
3556 
3557  if (isset($this->$sField)) {
3558  $sLongDesc = null;
3559  if ($this->$sField instanceof oxField) {
3560  $sLongDesc = $this->$sField->getRawValue();
3561  } elseif (is_object($this->$sField)) {
3562  $sLongDesc = $this->$sField->value;
3563  }
3564  if (isset($sLongDesc)) {
3565  $sAEField = $oArtExt->_getFieldLongName($sKey);
3566  $oArtExt->$sAEField = new oxField($sLongDesc, oxField::T_RAW);
3567  }
3568  }
3569  }
3570  }
3571  $oArtExt->save();
3572  }
3573  }
3574 
3578  protected function _skipSaveFields()
3579  {
3580  $myConfig = $this->getConfig();
3581 
3582  $this->_aSkipSaveFields = array();
3583 
3584  $this->_aSkipSaveFields[] = 'oxtimestamp';
3585  // $this->_aSkipSaveFields[] = 'oxlongdesc';
3586  $this->_aSkipSaveFields[] = 'oxinsert';
3588 
3589  if (!$this->_blAllowEmptyParentId && (!isset($this->oxarticles__oxparentid->value) || $this->oxarticles__oxparentid->value == '')) {
3590  $this->_aSkipSaveFields[] = 'oxparentid';
3591  }
3592 
3593  }
3594 
3604  protected function _mergeDiscounts($aDiscounts, $aItemDiscounts)
3605  {
3606  foreach ($aItemDiscounts as $sKey => $oDiscount) {
3607  // add prices of the same discounts
3608  if (array_key_exists($sKey, $aDiscounts)) {
3609  $aDiscounts[$sKey]->dDiscount += $oDiscount->dDiscount;
3610  } else {
3611  $aDiscounts[$sKey] = $oDiscount;
3612  }
3613  }
3614 
3615  return $aDiscounts;
3616  }
3617 
3623  protected function _getGroupPrice()
3624  {
3625  $sPriceSufix = $this->_getUserPriceSufix();
3626  $sVarName = "oxarticles__oxprice{$sPriceSufix}";
3627  $dPrice = $this->$sVarName->value;
3628 
3629  // #1437/1436C - added config option, and check for zero A,B,C price values
3630  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices') && (double) $dPrice == 0) {
3631  $dPrice = $this->oxarticles__oxprice->value;
3632  }
3633 
3634  return $dPrice;
3635  }
3636 
3645  protected function _getAmountPrice($dAmount = 1)
3646  {
3647  startProfile("_getAmountPrice");
3648 
3649  $dPrice = $this->_getGroupPrice();
3650  $oAmtPrices = $this->_getAmountPriceList();
3651  foreach ($oAmtPrices as $oAmPrice) {
3652  if ($oAmPrice->oxprice2article__oxamount->value <= $dAmount
3653  && $dAmount <= $oAmPrice->oxprice2article__oxamountto->value
3654  && $dPrice > $oAmPrice->oxprice2article__oxaddabs->value
3655  ) {
3656  $dPrice = $oAmPrice->oxprice2article__oxaddabs->value;
3657  }
3658  }
3659 
3660  stopProfile("_getAmountPrice");
3661 
3662  return $dPrice;
3663  }
3664 
3673  protected function _modifySelectListPrice($dPrice, $aChosenList = null)
3674  {
3675  $myConfig = $this->getConfig();
3676  // #690
3677  if ($myConfig->getConfigParam('bl_perfLoadSelectLists') && $myConfig->getConfigParam('bl_perfUseSelectlistPrice')) {
3678 
3679  $aSelLists = $this->getSelectLists();
3680 
3681  foreach ($aSelLists as $key => $aSel) {
3682  if (isset($aChosenList[$key]) && isset($aSel[$aChosenList[$key]])) {
3683  $oSel = $aSel[$aChosenList[$key]];
3684  if ($oSel->priceUnit == 'abs') {
3685  $dPrice += $oSel->price;
3686  } elseif ($oSel->priceUnit == '%') {
3687  $dPrice += oxPrice::percent($dPrice, $oSel->price);
3688  }
3689  }
3690  }
3691  }
3692 
3693  return $dPrice;
3694  }
3695 
3703  protected function _fillAmountPriceList($aAmPriceList)
3704  {
3705  $oLang = oxRegistry::getLang();
3706 
3707  // trying to find lowest price value
3708  foreach ($aAmPriceList as $sId => $oItem) {
3709 
3710  $oItemPrice = $this->_getPriceObject();
3711  if ($oItem->oxprice2article__oxaddabs->value) {
3712 
3713  $dBasePrice = $oItem->oxprice2article__oxaddabs->value;
3714  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
3715 
3716  $oItemPrice->setPrice($dBasePrice);
3717  $this->_calculatePrice($oItemPrice);
3718 
3719  } else {
3720  $dBasePrice = $this->_getGroupPrice();
3721  $dBasePrice = $this->_preparePrice($dBasePrice, $this->getArticleVat());
3722  $oItemPrice->setPrice($dBasePrice);
3723  $oItemPrice->subtractPercent($oItem->oxprice2article__oxaddperc->value);
3724  }
3725 
3726 
3727  $aAmPriceList[$sId]->fbrutprice = $oLang->formatCurrency($this->_getPriceForView($oItemPrice));
3728  }
3729 
3730  return $aAmPriceList;
3731  }
3732 
3740  public function getVariantIds($blActiveVariants = true)
3741  {
3742  $aSelect = array();
3743  $sId = $this->getId();
3744  if ($sId) {
3745  $sActiveSqlSnippet = "";
3746  if ($blActiveVariants) {
3747  $sActiveSqlSnippet = " and " . $this->getSqlActiveSnippet(true);
3748  }
3750  $sQ = "select oxid from " . $this->getViewName(true) . " where oxparentid = " . $oDb->quote($sId) .
3751  $sActiveSqlSnippet . " order by oxsort";
3752  $oRs = $oDb->select($sQ);
3753  if ($oRs != false && $oRs->recordCount() > 0) {
3754  while (!$oRs->EOF) {
3755  $aSelect[] = reset($oRs->fields);
3756  $oRs->moveNext();
3757  }
3758  }
3759  }
3760 
3761  return $aSelect;
3762  }
3763 
3773  protected function _getVariantsIds($blActiveVariants = true)
3774  {
3775  return $this->getVariantIds($blActiveVariants);
3776  }
3777 
3783  public function getArticleVat()
3784  {
3785  if (!isset($this->_dArticleVat)) {
3786  $this->_dArticleVat = oxRegistry::get("oxVatSelector")->getArticleVat($this);
3787  }
3788 
3789  return $this->_dArticleVat;
3790  }
3791 
3798  protected function _applyVAT(oxPrice $oPrice, $dVat)
3799  {
3800  startProfile(__FUNCTION__);
3801  $oPrice->setVAT($dVat);
3803  $oVatSelector = oxRegistry::get("oxVatSelector");
3804  if (($dVat = $oVatSelector->getArticleUserVat($this)) !== false) {
3805  $oPrice->setUserVat($dVat);
3806  }
3807  stopProfile(__FUNCTION__);
3808  }
3809 
3816  protected function _applyCurrency(oxPrice $oPrice, $oCur = null)
3817  {
3818  if (!$oCur) {
3819  $oCur = $this->getConfig()->getActShopCurrencyObject();
3820  }
3821 
3822  $oPrice->multiply($oCur->rate);
3823  }
3824 
3825 
3832  protected function _getAttribsString(&$sAttributeSql, &$iCnt)
3833  {
3834  // we do not use lists here as we don't need this overhead right now
3835  $oDb = oxDb::getDb();
3836  $sSelect = 'select oxattrid from oxobject2attribute where oxobject2attribute.oxobjectid=' . $oDb->quote($this->getId());
3837  if ($this->getParentId()) {
3838  $sSelect .= ' OR oxobject2attribute.oxobjectid=' . $oDb->quote($this->getParentId());
3839  }
3840  $sAttributeSql = '';
3841  $aAttributeIds = $oDb->getCol($sSelect);
3842  if (is_array($aAttributeIds) && count($aAttributeIds)) {
3843  $aAttributeIds = array_unique($aAttributeIds);
3844  $iCnt = count($aAttributeIds);
3845  $sAttributeSql .= 't1.oxattrid IN ( ' . implode(',', $oDb->quoteArray($aAttributeIds)) . ') ';
3846  }
3847  }
3848 
3857  protected function _getSimList($sAttributeSql, $iCnt)
3858  {
3859  // #523A
3860  $iAttrPercent = $this->getConfig()->getConfigParam('iAttributesPercent') / 100;
3861  // 70% same attributes
3862  if (!$iAttrPercent || $iAttrPercent < 0 || $iAttrPercent > 1) {
3863  $iAttrPercent = 0.70;
3864  }
3865  // #1137V iAttributesPercent = 100 doesn't work
3866  $iHitMin = ceil($iCnt * $iAttrPercent);
3867 
3868  $aExcludeIds = array();
3869  $aExcludeIds[] = $this->getId();
3870  if ($this->getParentId()) {
3871  $aExcludeIds[] = $this->getParentId();
3872  }
3873 
3874  // we do not use lists here as we don't need this overhead right now
3875  $sSelect = "select oxobjectid from oxobject2attribute as t1 where
3876  ( $sAttributeSql )
3877  and t1.oxobjectid NOT IN (" . implode(', ', oxDb::getDb()->quoteArray($aExcludeIds)) . ")
3878  group by t1.oxobjectid having count(*) >= $iHitMin LIMIT 0, 20";
3879 
3880  return oxDb::getDb()->getCol($sSelect);
3881  }
3882 
3891  protected function _generateSimListSearchStr($sArticleTable, $aList)
3892  {
3893  $sFieldList = $this->getSelectFields();
3894  $aList = array_slice($aList, 0, $this->getConfig()->getConfigParam('iNrofSimilarArticles'));
3895 
3896  $sSearch = "select $sFieldList from $sArticleTable where " . $this->getSqlActiveSnippet() . " and $sArticleTable.oxissearch = 1 and $sArticleTable.oxid in ( ";
3897 
3898  $sSearch .= implode(',', oxdb::getDb()->quoteArray($aList)) . ')';
3899 
3900  // #524A -- randomizing articles in attribute list
3901  $sSearch .= ' order by rand() ';
3902 
3903  return $sSearch;
3904  }
3905 
3914  protected function _generateSearchStr($sOXID, $blSearchPriceCat = false)
3915  {
3916 
3917  $sCatView = getViewName('oxcategories', $this->getLanguage());
3918  $sO2CView = getViewName('oxobject2category');
3919 
3920  // we do not use lists here as we don't need this overhead right now
3921  if (!$blSearchPriceCat) {
3922  $sSelect = "select {$sCatView}.* from {$sO2CView} as oxobject2category left join {$sCatView} on
3923  {$sCatView}.oxid = oxobject2category.oxcatnid
3924  where oxobject2category.oxobjectid=" . oxDb::getDb()->quote($sOXID) . " and {$sCatView}.oxid is not null ";
3925  } else {
3926  $sSelect = "select {$sCatView}.* from {$sCatView} where
3927  '{$this->oxarticles__oxprice->value}' >= {$sCatView}.oxpricefrom and
3928  '{$this->oxarticles__oxprice->value}' <= {$sCatView}.oxpriceto ";
3929  }
3930 
3931  return $sSelect;
3932  }
3933 
3940  {
3941  $sArtTable = $this->getViewName();
3942  $sOrderArtTable = getViewName('oxorderarticles');
3943 
3944  // fetching filter params
3945  $sIn = " '{$this->oxarticles__oxid->value}' ";
3946  if ($this->oxarticles__oxparentid->value) {
3947 
3948  // adding article parent
3949  $sIn .= ", '{$this->oxarticles__oxparentid->value}' ";
3950  $sParentIdForVariants = $this->oxarticles__oxparentid->value;
3951 
3952  } else {
3953  $sParentIdForVariants = $this->getId();
3954  }
3955 
3956  // adding variants
3958  $oRs = $oDb->select("select oxid from {$sArtTable} where oxparentid = " . $oDb->quote($sParentIdForVariants) . " and oxid != " . $oDb->quote($this->oxarticles__oxid->value));
3959  if ($oRs != false && $oRs->recordCount() > 0) {
3960  while (!$oRs->EOF) {
3961  $sIn .= ", " . $oDb->quote(current($oRs->fields)) . " ";
3962  $oRs->moveNext();
3963  }
3964  }
3965 
3966  $iLimit = (int) $this->getConfig()->getConfigParam('iNrofCustomerWhoArticles');
3967  $iLimit = $iLimit ? ($iLimit * 10) : 50;
3968 
3969  // building sql (optimized)
3970  $sQ = "select distinct {$sArtTable}.* from (
3971  select d.oxorderid as suborderid from {$sOrderArtTable} as d use index ( oxartid ) where d.oxartid in ( {$sIn} ) limit {$iLimit}
3972  ) as suborder
3973  left join {$sOrderArtTable} force index ( oxorderid ) on suborder.suborderid = {$sOrderArtTable}.oxorderid
3974  left join {$sArtTable} on {$sArtTable}.oxid = {$sOrderArtTable}.oxartid
3975  where {$sArtTable}.oxid not in ( {$sIn} )
3976  and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' ) and " . $this->getSqlActiveSnippet();
3977 
3978  /* non optimized, but could be used if index forcing is not supported
3979  // building sql
3980  $sQ = "select distinct {$sArtTable}.* from {$sOrderArtTable}, {$sArtTable} where {$sOrderArtTable}.oxorderid in (
3981  select {$sOrderArtTable}.oxorderid from {$sOrderArtTable} where {$sOrderArtTable}.oxartid in ( {$sIn} )
3982  ) and {$sArtTable}.oxid = {$sOrderArtTable}.oxartid and {$sArtTable}.oxid not in ( {$sIn} )
3983  and ( {$sArtTable}.oxissearch = 1 or {$sArtTable}.oxparentid <> '' )
3984  and ".$this->getSqlActiveSnippet();
3985  */
3986 
3987  return $sQ;
3988  }
3989 
3999  protected function _generateSelectCatStr($sOXID, $sCatId, $dPriceFromTo = false)
4000  {
4001  $sCategoryView = getViewName('oxcategories');
4002  $sO2CView = getViewName('oxobject2category');
4003 
4004  $oDb = oxDb::getDb();
4005  $sOXID = $oDb->quote($sOXID);
4006  $sCatId = $oDb->quote($sCatId);
4007 
4008  if (!$dPriceFromTo) {
4009  $sSelect = "select oxobject2category.oxcatnid from $sO2CView as oxobject2category ";
4010  $sSelect .= "left join $sCategoryView as oxcategories on oxcategories.oxid = oxobject2category.oxcatnid ";
4011  $sSelect .= "where oxobject2category.oxcatnid=$sCatId and oxobject2category.oxobjectid=$sOXID ";
4012  $sSelect .= "and oxcategories.oxactive = 1 order by oxobject2category.oxtime ";
4013  } else {
4014  $dPriceFromTo = $oDb->quote($dPriceFromTo);
4015  $sSelect = "select oxcategories.oxid from $sCategoryView as oxcategories where ";
4016  $sSelect .= "oxcategories.oxid=$sCatId and $dPriceFromTo >= oxcategories.oxpricefrom and ";
4017  $sSelect .= "$dPriceFromTo <= oxcategories.oxpriceto ";
4018  }
4019 
4020  return $sSelect;
4021  }
4022 
4028  protected function _getAmountPriceList()
4029  {
4030  if ($this->_oAmountPriceList === null) {
4031  $oAmPriceList = oxNew('oxAmountPricelist');
4032 
4033  if (!$this->skipDiscounts()) {
4034  //collecting assigned to article amount-price list
4035  $oAmPriceList->load($this);
4036 
4037  // prepare abs prices if currently having percentages
4038  $oBasePrice = $this->_getGroupPrice();
4039  foreach ($oAmPriceList as $oAmPrice) {
4040  if ($oAmPrice->oxprice2article__oxaddperc->value) {
4041  $oAmPrice->oxprice2article__oxaddabs = new oxField(oxPrice::percent($oBasePrice, 100 - $oAmPrice->oxprice2article__oxaddperc->value), oxField::T_RAW);
4042  }
4043  }
4044 
4045  }
4046 
4047  $this->_oAmountPriceList = $oAmPriceList;
4048  }
4049 
4050  return $this->_oAmountPriceList;
4051  }
4052 
4060  protected function _isFieldEmpty($sFieldName)
4061  {
4062  $mValue = $this->$sFieldName->value;
4063 
4064  if (is_null($mValue)) {
4065  return true;
4066  }
4067 
4068  if ($mValue === '') {
4069  return true;
4070  }
4071 
4072  // certain fields with zero value treat as empty
4073  $aZeroValueFields = array('oxarticles__oxprice', 'oxarticles__oxvat', 'oxarticles__oxunitquantity');
4074 
4075  if (!$mValue && in_array($sFieldName, $aZeroValueFields)) {
4076  return true;
4077  }
4078 
4079 
4080  if (!strcmp($mValue, '0000-00-00 00:00:00') || !strcmp($mValue, '0000-00-00')) {
4081  return true;
4082  }
4083 
4084  $sFieldName = strtolower($sFieldName);
4085 
4086  if ($sFieldName == 'oxarticles__oxicon' && (strpos($mValue, "nopic_ico.jpg") !== false || strpos($mValue, "nopic.jpg") !== false)) {
4087  return true;
4088  }
4089 
4090  if (strpos($mValue, "nopic.jpg") !== false && ($sFieldName == 'oxarticles__oxthumb' || substr($sFieldName, 0, 17) == 'oxarticles__oxpic' || substr($sFieldName, 0, 18) == 'oxarticles__oxzoom')) {
4091  return true;
4092  }
4093 
4094  return false;
4095  }
4096 
4104  protected function _assignParentFieldValue($sFieldName)
4105  {
4106  if (!($oParentArticle = $this->getParentArticle())) {
4107  return;
4108  }
4109 
4110  $sCopyFieldName = $this->_getFieldLongName($sFieldName);
4111 
4112  // assigning only these which parent article has
4113  if ($oParentArticle->$sCopyFieldName != null) {
4114 
4115  // only overwrite database values
4116  if (substr($sCopyFieldName, 0, 12) != 'oxarticles__') {
4117  return;
4118  }
4119 
4120  //do not copy certain fields
4121  if (in_array($sCopyFieldName, $this->_aNonCopyParentFields)) {
4122  return;
4123  }
4124 
4125  //skip picture parent value assignment in case master image is set for variant
4126  if ($this->_isFieldEmpty($sCopyFieldName) && $this->_isImageField($sCopyFieldName) && $this->_hasMasterImage(1)) {
4127  return;
4128  }
4129 
4130  //COPY THE VALUE
4131  if ($this->_isFieldEmpty($sCopyFieldName)) {
4132  $this->$sCopyFieldName = clone $oParentArticle->$sCopyFieldName;
4133  }
4134  }
4135  }
4136 
4144  protected function _isImageField($sFieldName)
4145  {
4146  $blIsImageField = (stristr($sFieldName, '_oxthumb') || stristr($sFieldName, '_oxicon') || stristr($sFieldName, '_oxzoom') || stristr($sFieldName, '_oxpic'));
4147 
4148  return $blIsImageField;
4149  }
4150 
4154  protected function _assignParentFieldValues()
4155  {
4156  startProfile('articleAssignParentInternal');
4157  if ($this->oxarticles__oxparentid->value) {
4158  // yes, we are in fact a variant
4159  if (!$this->isAdmin() || ($this->_blLoadParentData && $this->isAdmin())) {
4160  foreach ($this->_aFieldNames as $sFieldName => $sVal) {
4161  $this->_assignParentFieldValue($sFieldName);
4162  }
4163  }
4164  }
4165  stopProfile('articleAssignParentInternal');
4166  }
4167 
4171  protected function _assignNotBuyableParent()
4172  {
4173  if (!$this->getConfig()->getConfigParam('blVariantParentBuyable') &&
4174  ($this->_blHasVariants || $this->oxarticles__oxvarstock->value || $this->oxarticles__oxvarcount->value)
4175  ) {
4176  $this->_blNotBuyableParent = true;
4177 
4178  }
4179  }
4180 
4184  protected function _assignStock()
4185  {
4186  $myConfig = $this->getConfig();
4187  // -----------------------------------
4188  // stock
4189  // -----------------------------------
4190 
4191  // #1125 A. must round (using floor()) value taken from database and cast to int
4192  if (!$myConfig->getConfigParam('blAllowUnevenAmounts') && !$this->isAdmin()) {
4193  $this->oxarticles__oxstock = new oxField((int) floor($this->oxarticles__oxstock->value));
4194  }
4195  //GREEN light
4196  $this->_iStockStatus = 0;
4197 
4198  // if we have flag /*1 or*/ 4 - we show always green light
4199  if ($myConfig->getConfigParam('blUseStock') && /*$this->oxarticles__oxstockflag->value != 1 && */
4200  $this->oxarticles__oxstockflag->value != 4
4201  ) {
4202  //ORANGE light
4203  $iStock = $this->oxarticles__oxstock->value;
4204 
4205  if ($this->_blNotBuyableParent) {
4206  $iStock = $this->oxarticles__oxvarstock->value;
4207  }
4208 
4209 
4210  if ($iStock <= $myConfig->getConfigParam('sStockWarningLimit') && $iStock > 0) {
4211  $this->_iStockStatus = 1;
4212  }
4213 
4214  //RED light
4215  if ($iStock <= 0) {
4216  $this->_iStockStatus = -1;
4217  }
4218  }
4219 
4220 
4221  // stock
4222  if ($myConfig->getConfigParam('blUseStock') && ($this->oxarticles__oxstockflag->value == 3 || $this->oxarticles__oxstockflag->value == 2)) {
4223  $iOnStock = $this->oxarticles__oxstock->value;
4224  if ($this->getConfig()->getConfigParam('blPsBasketReservationEnabled')) {
4225  $iOnStock += $this->getSession()->getBasketReservations()->getReservedAmount($this->getId());
4226  }
4227  if ($iOnStock <= 0) {
4228  $this->setBuyableState(false);
4229  }
4230  }
4231 
4232  //exceptional handling for variant parent stock:
4233  if ($this->_blNotBuyable && $this->oxarticles__oxvarstock->value) {
4234  $this->setBuyableState(true);
4235  //but then at least setting notBuaybleParent to true
4236  $this->_blNotBuyableParent = true;
4237  }
4238 
4239  //special treatment for lists when blVariantParentBuyable config option is set to false
4240  //then we just hide "to basket" button.
4241  //if variants are not loaded in the list and this article has variants and parent is not buyable then this article is not buyable
4242  if (!$myConfig->getConfigParam('blVariantParentBuyable') && !$myConfig->getConfigParam('blLoadVariants') && $this->oxarticles__oxvarstock->value) {
4243  $this->setBuyableState(false);
4244  }
4245 
4246  //setting to non buyable when variant list is empty (for example not loaded or inactive) and $this is non buyable parent
4247  if (!$this->_blNotBuyable && $this->_blNotBuyableParent && $this->oxarticles__oxvarcount->value == 0) {
4248  $this->setBuyableState(false);
4249  }
4250  }
4251 
4255  protected function _assignPersistentParam()
4256  {
4257  // Persistent Parameter Handling
4258  $aPersParam = oxRegistry::getSession()->getVariable('persparam');
4259  if (isset($aPersParam) && isset($aPersParam[$this->getId()])) {
4260  $this->_aPersistParam = $aPersParam[$this->getId()];
4261  }
4262  }
4263 
4267  protected function _assignDynImageDir()
4268  {
4269  $myConfig = $this->getConfig();
4270 
4271  $sThisShop = $this->oxarticles__oxshopid->value;
4272 
4273  $this->_sDynImageDir = $myConfig->getPictureUrl(null, false);
4274  $this->dabsimagedir = $myConfig->getPictureDir(false); //$sThisShop
4275  $this->nossl_dimagedir = $myConfig->getPictureUrl(null, false, false, null, $sThisShop); //$sThisShop
4276  $this->ssl_dimagedir = $myConfig->getPictureUrl(null, false, true, null, $sThisShop); //$sThisShop
4277  }
4278 
4282  protected function _assignComparisonListFlag()
4283  {
4284  // #657 add a flag if article is on comparisonlist
4285 
4286  $aItems = oxRegistry::getSession()->getVariable('aFiltcompproducts');
4287  if (isset($aItems[$this->getId()])) {
4288  $this->_blIsOnComparisonList = true;
4289  }
4290  }
4291 
4299  protected function _insert()
4300  {
4301  // set oxinsert
4302  $sNow = date('Y-m-d H:i:s', oxRegistry::get("oxUtilsDate")->getTime());
4303  $this->oxarticles__oxinsert = new oxField($sNow);
4304  if (!is_object($this->oxarticles__oxsubclass) || $this->oxarticles__oxsubclass->value == '') {
4305  $this->oxarticles__oxsubclass = new oxField('oxarticle');
4306  }
4307 
4308  $blRes = parent::_insert();
4309 
4310 
4311  return $blRes;
4312  }
4313 
4319  protected function _update()
4320  {
4321 
4322  $this->setUpdateSeo(true);
4323  $this->_setUpdateSeoOnFieldChange('oxtitle');
4324 
4325  $this->_skipSaveFields();
4326 
4327  $myConfig = $this->getConfig();
4328 
4329 
4330  $blRes = parent::_update();
4331 
4332 
4333  return $blRes;
4334  }
4335 
4343  protected function _deleteRecords($sOXID)
4344  {
4345  $oDb = oxDb::getDb();
4346 
4347  $sOXID = $oDb->quote($sOXID);
4348 
4349  //remove other records
4350  $sDelete = 'delete from oxobject2article where oxarticlenid = ' . $sOXID . ' or oxobjectid = ' . $sOXID . ' ';
4351  $oDb->execute($sDelete);
4352 
4353  $sDelete = 'delete from oxobject2attribute where oxobjectid = ' . $sOXID . ' ';
4354  $oDb->execute($sDelete);
4355 
4356  $sDelete = 'delete from oxobject2category where oxobjectid = ' . $sOXID . ' ';
4357  $oDb->execute($sDelete);
4358 
4359  $sDelete = 'delete from oxobject2selectlist where oxobjectid = ' . $sOXID . ' ';
4360  $oDb->execute($sDelete);
4361 
4362  $sDelete = 'delete from oxprice2article where oxartid = ' . $sOXID . ' ';
4363  $oDb->execute($sDelete);
4364 
4365  $sDelete = 'delete from oxreviews where oxtype="oxarticle" and oxobjectid = ' . $sOXID . ' ';
4366  $oDb->execute($sDelete);
4367 
4368  $sDelete = 'delete from oxratings where oxobjectid = ' . $sOXID . ' ';
4369  $rs = $oDb->execute($sDelete);
4370 
4371  $sDelete = 'delete from oxaccessoire2article where oxobjectid = ' . $sOXID . ' or oxarticlenid = ' . $sOXID . ' ';
4372  $oDb->execute($sDelete);
4373 
4374  //#1508C - deleting oxobject2delivery entries added
4375  $sDelete = 'delete from oxobject2delivery where oxobjectid = ' . $sOXID . ' and oxtype=\'oxarticles\' ';
4376  $oDb->execute($sDelete);
4377 
4378  $sDelete = 'delete from oxartextends where oxid = ' . $sOXID . ' ';
4379  $oDb->execute($sDelete);
4380 
4381  //delete the record
4382  foreach ($this->_getLanguageSetTables("oxartextends") as $sSetTbl) {
4383  $oDb->execute("delete from $sSetTbl where oxid = {$sOXID}");
4384  }
4385 
4386  $sDelete = 'delete from oxactions2article where oxartid = ' . $sOXID . ' ';
4387  $rs = $oDb->execute($sDelete);
4388 
4389  $sDelete = 'delete from oxobject2list where oxobjectid = ' . $sOXID . ' ';
4390  $rs = $oDb->execute($sDelete);
4391 
4392 
4393  return $rs;
4394  }
4395 
4401  protected function _deleteVariantRecords($sOXID)
4402  {
4403  if ($sOXID) {
4404  $oDb = oxDb::getDb();
4405  //collect variants to remove recursively
4406  $sQ = 'select oxid from ' . $this->getViewName() . ' where oxparentid = ' . $oDb->quote($sOXID);
4407  $rs = $oDb->select($sQ, false, false);
4408  $oArticle = oxNew("oxArticle");
4409  if ($rs != false && $rs->recordCount() > 0) {
4410  while (!$rs->EOF) {
4411  $oArticle->setId($rs->fields[0]);
4412  $oArticle->delete();
4413  $rs->moveNext();
4414  }
4415  }
4416  }
4417  }
4418 
4422  protected function _deletePics()
4423  {
4424  $myUtilsPic = oxRegistry::get("oxUtilsPic");
4425  $myConfig = $this->getConfig();
4426  $oPictureHandler = oxRegistry::get("oxPictureHandler");
4427 
4428  //deleting custom main icon
4429  $oPictureHandler->deleteMainIcon($this);
4430 
4431  //deleting custom thumbnail
4432  $oPictureHandler->deleteThumbnail($this);
4433 
4434  $sAbsDynImageDir = $myConfig->getPictureDir(false);
4435 
4436  // deleting master image and all generated images
4437  $iPicCount = $myConfig->getConfigParam('iPicCount');
4438  for ($i = 1; $i <= $iPicCount; $i++) {
4439  $oPictureHandler->deleteArticleMasterPicture($this, $i);
4440  }
4441  }
4442 
4450  protected function _onChangeResetCounts($sOxid, $sVendorId = null, $sManufacturerId = null)
4451  {
4452  $myUtilsCount = oxRegistry::get("oxUtilsCount");
4453 
4454  if ($sVendorId) {
4455  $myUtilsCount->resetVendorArticleCount($sVendorId);
4456  }
4457 
4458  if ($sManufacturerId) {
4459  $myUtilsCount->resetManufacturerArticleCount($sManufacturerId);
4460  }
4461 
4462  $aCategoryIds = $this->getCategoryIds();
4463  //also reseting category counts
4464  foreach ($aCategoryIds as $sCatId) {
4465  $myUtilsCount->resetCatArticleCount($sCatId, false);
4466  }
4467  }
4468 
4474  protected function _onChangeUpdateStock($sParentID)
4475  {
4476  if ($sParentID) {
4477  $oDb = oxDb::getDb();
4478  $sParentIdQuoted = $oDb->quote($sParentID);
4479  $sQ = 'select oxstock, oxvendorid, oxmanufacturerid from oxarticles where oxid = ' . $sParentIdQuoted;
4480  $rs = $oDb->select($sQ, false, false);
4481  $iOldStock = $rs->fields[0];
4482  $iVendorID = $rs->fields[1];
4483  $iManufacturerID = $rs->fields[2];
4484 
4485  $sQ = 'select sum(oxstock) from ' . $this->getViewName(true) . ' where oxparentid = ' . $sParentIdQuoted . ' and ' . $this->getSqlActiveSnippet(true) . ' and oxstock > 0 ';
4486  $iStock = (float) $oDb->getOne($sQ, false, false);
4487 
4488  $sQ = 'update oxarticles set oxvarstock = ' . $iStock . ' where oxid = ' . $sParentIdQuoted;
4489  $oDb->execute($sQ);
4490 
4491  //now lets update category counts
4492  //first detect stock status change for this article (to or from 0)
4493  if ($iStock < 0) {
4494  $iStock = 0;
4495  }
4496  if ($iOldStock < 0) {
4497  $iOldStock = 0;
4498  }
4499  if ($this->oxarticles__oxstockflag->value == 2 && $iOldStock xor $iStock) {
4500  //means the stock status could be changed (oxstock turns from 0 to 1 or from 1 to 0)
4501  // so far we leave it like this but later we could move all count resets to one or two functions
4502  $this->_onChangeResetCounts($sParentID, $iVendorID, $iManufacturerID);
4503  }
4504  }
4505  }
4506 
4512  protected function _onChangeStockResetCount($sOxid)
4513  {
4514  $myConfig = $this->getConfig();
4515 
4516  if ($myConfig->getConfigParam('blUseStock') && $this->oxarticles__oxstockflag->value == 2 &&
4517  ($this->oxarticles__oxstock->value + $this->oxarticles__oxvarstock->value) <= 0
4518  ) {
4519 
4520  $this->_onChangeResetCounts($sOxid, $this->oxarticles__oxvendorid->value, $this->oxarticles__oxmanufacturerid->value);
4521  }
4522  }
4523 
4529  protected function _onChangeUpdateVarCount($sParentID)
4530  {
4531  if ($sParentID) {
4532  $oDb = oxDb::getDb();
4533  $sParentIdQuoted = $oDb->quote($sParentID);
4534  $sQ = "select count(*) as varcount from oxarticles where oxparentid = {$sParentIdQuoted}";
4535  $iVarCount = (int) $oDb->getOne($sQ, false, false);
4536 
4537  $sQ = "update oxarticles set oxvarcount = {$iVarCount} where oxid = {$sParentIdQuoted}";
4538  $oDb->execute($sQ);
4539  }
4540  }
4541 
4547  protected function _setVarMinMaxPrice($sParentId)
4548  {
4549  if ($sParentId) {
4551  $sQ = '
4552  SELECT
4553  MIN( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varminprice`,
4554  MAX( IF( `oxarticles`.`oxprice` > 0, `oxarticles`.`oxprice`, `p`.`oxprice` ) ) AS `varmaxprice`
4555  FROM ' . $this->getViewName(true) . ' AS `oxarticles`
4556  LEFT JOIN ' . $this->getViewName(true) . ' AS `p` ON ( `p`.`oxid` = `oxarticles`.`oxparentid` AND `p`.`oxprice` > 0 )
4557  WHERE ' . $this->getSqlActiveSnippet(true) . '
4558  AND ( `oxarticles`.`oxparentid` = ' . $oDb->quote($sParentId) . ' )';
4559  $oDb->setFetchMode(oxDb::FETCH_MODE_ASSOC);
4560  $aPrices = $oDb->getRow($sQ, false, false);
4561  if (!is_null($aPrices['varminprice']) || !is_null($aPrices['varmaxprice'])) {
4562  $sQ = '
4563  UPDATE `oxarticles`
4564  SET
4565  `oxvarminprice` = ' . $oDb->quote($aPrices['varminprice']) . ',
4566  `oxvarmaxprice` = ' . $oDb->quote($aPrices['varmaxprice']) . '
4567  WHERE
4568  `oxid` = ' . $oDb->quote($sParentId);
4569  } else {
4570  $sQ = '
4571  UPDATE `oxarticles`
4572  SET
4573  `oxvarminprice` = `oxprice`,
4574  `oxvarmaxprice` = `oxprice`
4575  WHERE
4576  `oxid` = ' . $oDb->quote($sParentId);
4577  }
4578  $oDb->execute($sQ);
4579  }
4580  }
4581 
4589  protected function _hasMasterImage($iIndex)
4590  {
4591  $sPicName = basename($this->{"oxarticles__oxpic" . $iIndex}->value);
4592 
4593  if ($sPicName == "nopic.jpg" || $sPicName == "") {
4594  return false;
4595  }
4596  if ($this->isVariant() &&
4597  $this->getParentArticle() &&
4598  $this->getParentArticle()->{"oxarticles__oxpic" . $iIndex}->value == $this->{"oxarticles__oxpic" . $iIndex}->value
4599  ) {
4600  return false;
4601  }
4602 
4603  $sMasterPic = 'product/' . $iIndex . "/" . $sPicName;
4604 
4605  if ($this->getConfig()->getMasterPicturePath($sMasterPic)) {
4606  return true;
4607  }
4608 
4609  return false;
4610  }
4611 
4617  protected function _isPriceViewModeNetto()
4618  {
4619  $blResult = (bool) $this->getConfig()->getConfigParam('blShowNetPrice');
4620  $oUser = $this->getArticleUser();
4621  if ($oUser) {
4622  $blResult = $oUser->isPriceViewModeNetto();
4623  }
4624 
4625  return $blResult;
4626  }
4627 
4628 
4636  protected function _getPriceObject($blCalculationModeNetto = null)
4637  {
4638  $oPrice = oxNew('oxPrice');
4639 
4640  if ($blCalculationModeNetto === null) {
4641  $blCalculationModeNetto = $this->_isPriceViewModeNetto();
4642  }
4643 
4644  if ($blCalculationModeNetto) {
4645  $oPrice->setNettoPriceMode();
4646  } else {
4647  $oPrice->setBruttoPriceMode();
4648  }
4649 
4650  return $oPrice;
4651  }
4652 
4653 
4661  protected function _getPriceForView($oPrice)
4662  {
4663  if ($this->_isPriceViewModeNetto()) {
4664  $dPrice = $oPrice->getNettoPrice();
4665  } else {
4666  $dPrice = $oPrice->getBruttoPrice();
4667  }
4668 
4669  return $dPrice;
4670  }
4671 
4672 
4682  protected function _preparePrice($dPrice, $dVat, $blCalculationModeNetto = null)
4683  {
4684  if ($blCalculationModeNetto === null) {
4685  $blCalculationModeNetto = $this->_isPriceViewModeNetto();
4686  }
4687 
4688  $oCurrency = $this->getConfig()->getActShopCurrencyObject();
4689 
4690  $blEnterNetPrice = $this->getConfig()->getConfigParam('blEnterNetPrice');
4691  if ($blCalculationModeNetto && !$blEnterNetPrice) {
4692  $dPrice = round(oxPrice::brutto2Netto($dPrice, $dVat), $oCurrency->decimal);
4693  } elseif (!$blCalculationModeNetto && $blEnterNetPrice) {
4694  $dPrice = round(oxPrice::netto2Brutto($dPrice, $dVat), $oCurrency->decimal);
4695  }
4696 
4697  return $dPrice;
4698  }
4699 
4705  protected function _getUserPriceSufix()
4706  {
4707  $sPriceSuffix = '';
4708  $oUser = $this->getArticleUser();
4709 
4710  if ($oUser) {
4711  if ($oUser->inGroup('oxidpricea')) {
4712  $sPriceSuffix = 'a';
4713  } elseif ($oUser->inGroup('oxidpriceb')) {
4714  $sPriceSuffix = 'b';
4715  } elseif ($oUser->inGroup('oxidpricec')) {
4716  $sPriceSuffix = 'c';
4717  }
4718  }
4719 
4720  return $sPriceSuffix;
4721  }
4722 
4723 
4729  protected function _getPrice()
4730  {
4731  $sPriceSuffix = $this->_getUserPriceSufix();
4732  if ($sPriceSuffix === '') {
4733  $dPrice = $this->oxarticles__oxprice->value;
4734  } else {
4735  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4736  $dPrice = ($this->{oxarticles__oxprice . $sPriceSuffix}->value != 0) ? $this->{oxarticles__oxprice . $sPriceSuffix}->value : $this->oxarticles__oxprice->value;
4737  } else {
4738  $dPrice = $this->{oxarticles__oxprice . $sPriceSuffix}->value;
4739  }
4740  }
4741 
4742  return $dPrice;
4743  }
4744 
4745 
4751  protected function _getVarMinPrice()
4752  {
4753  if ($this->_dVarMinPrice === null) {
4754  $dPrice = null;
4755 
4756 
4757  if (is_null($dPrice)) {
4758  $sPriceSuffix = $this->_getUserPriceSufix();
4759  if ($sPriceSuffix === '') {
4760  $dPrice = $this->oxarticles__oxvarminprice->value;
4761  } else {
4762  $sSql = 'SELECT ';
4763  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4764  $sSql .= 'MIN( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varminprice` ';
4765  } else {
4766  $sSql .= 'MIN(`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
4767  }
4768 
4769  $sSql .= ' FROM ' . $this->getViewName(true) . '
4770  WHERE ' . $this->getSqlActiveSnippet(true) . '
4771  AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
4772 
4773  $dPrice = oxDb::getDb()->getOne($sSql);
4774  }
4775  }
4776 
4777  $this->_dVarMinPrice = $dPrice;
4778  }
4779 
4780  return $this->_dVarMinPrice;
4781  }
4782 
4788  protected function _getSubShopVarMinPrice()
4789  {
4790  $myConfig = $this->getConfig();
4791  $sShopId = $myConfig->getShopId();
4792  if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
4793  $sPriceSuffix = $this->_getUserPriceSufix();
4794  $sSql = 'SELECT ';
4795  if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4796  $sSql .= 'MIN(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varminprice` ';
4797  } else {
4798  $sSql .= 'MIN(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varminprice` ';
4799  }
4800  $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
4801  INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
4802  WHERE ' . $this->getSqlActiveSnippet(true) . '
4803  AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
4804  AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
4805  $dPrice = oxDb::getDb()->getOne($sSql);
4806  }
4807 
4808  return $dPrice;
4809  }
4810 
4816  protected function _getVarMaxPrice()
4817  {
4818  if ($this->_dVarMaxPrice === null) {
4819 
4820  $dPrice = null;
4821 
4822  if (is_null($dPrice)) {
4823  $sPriceSuffix = $this->_getUserPriceSufix();
4824  if ($sPriceSuffix === '') {
4825  $dPrice = $this->oxarticles__oxvarmaxprice->value;
4826  } else {
4827  $sSql = 'SELECT ';
4828  if ($this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4829  $sSql .= 'MAX( IF(`oxprice' . $sPriceSuffix . '` = 0, `oxprice`, `oxprice' . $sPriceSuffix . '`) ) AS `varmaxprice` ';
4830  } else {
4831  $sSql .= 'MAX(`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
4832  }
4833 
4834  $sSql .= ' FROM ' . $this->getViewName(true) . '
4835  WHERE ' . $this->getSqlActiveSnippet(true) . '
4836  AND ( `oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )';
4837 
4838  $dPrice = oxDb::getDb()->getOne($sSql);
4839  }
4840  }
4841 
4842  $this->_dVarMaxPrice = $dPrice;
4843  }
4844 
4845  return $this->_dVarMaxPrice;
4846  }
4847 
4853  protected function _getSubShopVarMaxPrice()
4854  {
4855  $myConfig = $this->getConfig();
4856  $sShopId = $myConfig->getShopId();
4857  if ($this->getConfig()->getConfigParam('blMallCustomPrice') && $sShopId != $this->oxarticles__oxshopid->value) {
4858  $sPriceSuffix = $this->_getUserPriceSufix();
4859  $sSql = 'SELECT ';
4860  if ($sPriceSuffix != '' && $this->getConfig()->getConfigParam('blOverrideZeroABCPrices')) {
4861  $sSql .= 'MAX(IF(`oxfield2shop`.`oxprice' . $sPriceSuffix . '` = 0, `oxfield2shop`.`oxprice`, `oxfield2shop`.`oxprice' . $sPriceSuffix . '`)) AS `varmaxprice` ';
4862  } else {
4863  $sSql .= 'MAX(`oxfield2shop`.`oxprice' . $sPriceSuffix . '`) AS `varmaxprice` ';
4864  }
4865  $sSql .= ' FROM ' . getViewName('oxfield2shop') . ' AS oxfield2shop
4866  INNER JOIN ' . $this->getViewName(true) . ' AS oxarticles ON `oxfield2shop`.`oxartid` = `oxarticles`.`oxid`
4867  WHERE ' . $this->getSqlActiveSnippet(true) . '
4868  AND ( `oxarticles`.`oxparentid` = ' . oxDb::getDb()->quote($this->getId()) . ' )
4869  AND ( `oxfield2shop`.`oxshopid` = ' . oxDb::getDb()->quote($sShopId) . ' )';
4870  $dPrice = oxDb::getDb()->getOne($sSql);
4871  }
4872 
4873  return $dPrice;
4874  }
4875 
4883  protected function _loadFromDb($sOXID)
4884  {
4885 
4886  $sSelect = $this->buildSelectString(array($this->getViewName() . ".oxid" => $sOXID));
4887 
4888 
4889  $aData = oxDb::getDb(oxDb::FETCH_MODE_ASSOC)->getRow($sSelect);
4890 
4891  return $aData;
4892  }
4893 
4899  protected function _updateParentDependFields()
4900  {
4901  $oDb = oxDb::getDb();
4902 
4903  foreach ($this->_getCopyParentFields() as $sField) {
4904  $sValue = isset($this->$sField->value) ? $this->$sField->value : 0;
4905  $sSqlSets[] = '`' . str_replace('oxarticles__', '', $sField) . '` = ' . $oDb->quote($sValue);
4906  }
4907 
4908  $sSql = "UPDATE `oxarticles` SET ";
4909  $sSql .= implode(', ', $sSqlSets) . '';
4910  $sSql .= " WHERE `oxparentid` = " . $oDb->quote($this->getId());
4911 
4912  return $oDb->execute($sSql);
4913  }
4914 
4915 
4921  protected function _getCopyParentFields()
4922  {
4923  return $this->_aCopyParentField;
4924  }
4925 
4929  protected function _assignParentDependFields()
4930  {
4931  $sParent = $this->getParentArticle();
4932  if ($sParent) {
4933  foreach ($this->_getCopyParentFields() as $sField) {
4934  $this->$sField = new oxField($sParent->$sField->value);
4935  }
4936  }
4937  }
4938 
4939 
4940 
4944  protected function _saveSortingFieldValuesOnLoad()
4945  {
4946  $aSortingFields = oxRegistry::getConfig()->getConfigParam('aSortCols');
4947  $aSortingFields = !empty($aSortingFields) ? (array) $aSortingFields : array();
4948 
4949  foreach ($aSortingFields as $sField) {
4950  $sFullField = $this->_getFieldLongName($sField);
4951  $this->_aSortingFieldsOnLoad[$sFullField] = $this->$sFullField->value;
4952  }
4953  }
4954 }