/** * Copy or paste a single variant * @return string */ protected function pasteVariant($objProduct, $table, $row, $arrClipboard) { // Can't copy variant into it's current product if ($table == 'tl_iso_product' && $objProduct->pid == $row['id'] && $arrClipboard['mode'] == 'copy') { return $this->getPasteButton(false); } elseif ($table == 'tl_iso_product' && $row['id'] > 0) { $objType = ProductType::findByPk($row['type']); if (null === $objType || !$objType->hasVariants()) { return $this->getPasteButton(false); } } return $this->getPasteButton(true, $this->addToUrl('act=' . $arrClipboard['mode'] . '&mode=2&pid=' . $row['id']), $table, $row['id']); }
/** * Generate a product label and return it as HTML string * @param array * @param string * @param object * @param array * @return string */ public function generate($row, $label, $dc, $args) { $objProduct = Product::findByPk($row['id']); foreach ($GLOBALS['TL_DCA'][$dc->table]['list']['label']['fields'] as $i => $field) { switch ($field) { // Add an image case 'images': $arrImages = deserialize($objProduct->images); $args[$i] = ' '; if (is_array($arrImages) && !empty($arrImages)) { foreach ($arrImages as $image) { $strImage = 'isotope/' . strtolower(substr($image['src'], 0, 1)) . '/' . $image['src']; if (!is_file(TL_ROOT . '/' . $strImage)) { continue; } $size = @getimagesize(TL_ROOT . '/' . $strImage); $args[$i] = sprintf('<a href="%s" onclick="Backend.openModalImage({\'width\':%s,\'title\':\'%s\',\'url\':\'%s\'});return false"><img src="%s" alt="%s" align="left"></a>', $strImage, $size[0], str_replace("'", "\\'", $objProduct->name), $strImage, \Image::get($strImage, 50, 50, 'proportional'), $image['alt']); break; } } break; case 'name': $args[$i] = $objProduct->name; /** @var \Isotope\Model\ProductType $objProductType */ if ($row['pid'] == 0 && ($objProductType = ProductType::findByPk($row['type'])) !== null && $objProductType->hasVariants()) { // Add a variants link $args[$i] = sprintf('<a href="%s" title="%s">%s</a>', ampersand(\Environment::get('request')) . '&id=' . $row['id'], specialchars($GLOBALS['TL_LANG'][$dc->table]['showVariants']), $args[$i]); } break; case 'price': $objPrice = ProductPrice::findPrimaryByProductId($row['id']); if (null !== $objPrice) { /** @var \Isotope\Model\TaxClass $objTax */ $objTax = $objPrice->getRelated('tax_class'); $strTax = null === $objTax ? '' : ' (' . $objTax->getName() . ')'; $args[$i] = $objPrice->getValueForTier(1) . $strTax; } break; case 'variantFields': $attributes = array(); foreach ($GLOBALS['TL_DCA'][$dc->table]['list']['label']['variantFields'] as $variantField) { $attributes[] = '<strong>' . Format::dcaLabel($dc->table, $variantField) . ':</strong> ' . Format::dcaValue($dc->table, $variantField, $objProduct->{$variantField}); } $args[$i] = ($args[$i] ? $args[$i] . '<br>' : '') . implode(', ', $attributes); break; } } return $args; }
protected function compile() { $periodFactory = new PeriodFactory(); $arrSession = \Session::getInstance()->get('iso_reports'); $strPeriod = (string) $arrSession[$this->name]['period']; $intColumns = (int) $arrSession[$this->name]['columns']; $blnVariants = (bool) $arrSession[$this->name]['variants']; $intStatus = (int) $arrSession[$this->name]['iso_status']; if ($arrSession[$this->name]['from'] == '') { $intStart = strtotime('-' . ($intColumns - 1) . ' ' . $strPeriod); } else { $intStart = (int) $arrSession[$this->name]['from']; } $period = $periodFactory->create($strPeriod); $intStart = $period->getPeriodStart($intStart); $dateFrom = $period->getKey($intStart); $dateTo = $period->getKey(strtotime('+ ' . ($intColumns - 1) . ' ' . $strPeriod, $intStart)); $arrData = array('rows' => array()); $arrData['header'] = $this->getHeader($period, $intStart, $intColumns); $groupVariants = $blnVariants ? 'p1.id' : 'IF(p1.pid=0, p1.id, p1.pid)'; $objProducts = \Database::getInstance()->query("\n SELECT\n IFNULL({$groupVariants}, i.product_id) AS product_id,\n IFNULL(p1.name, i.name) AS variant_name,\n IFNULL(p2.name, i.name) AS product_name,\n p1.sku AS product_sku,\n p2.sku AS variant_sku,\n IF(p1.pid=0, p1.type, p2.type) AS type,\n i.configuration AS product_configuration,\n SUM(i.quantity) AS quantity,\n SUM(i.tax_free_price * i.quantity) AS total,\n " . $period->getSqlField($this->strDateField) . " AS dateGroup\n FROM " . ProductCollectionItem::getTable() . " i\n LEFT JOIN " . ProductCollection::getTable() . " o ON i.pid=o.id\n LEFT JOIN " . OrderStatus::getTable() . " os ON os.id=o.order_status\n LEFT OUTER JOIN " . Product::getTable() . " p1 ON i.product_id=p1.id\n LEFT OUTER JOIN " . Product::getTable() . " p2 ON p1.pid=p2.id\n WHERE o.type='order' AND o.order_status>0 AND o.locked!=''\n " . ($intStatus > 0 ? " AND o.order_status=" . $intStatus : '') . "\n " . $this->getProductProcedure('p1') . "\n " . $this->getConfigProcedure('o', 'config_id') . "\n GROUP BY dateGroup, product_id\n HAVING dateGroup>={$dateFrom} AND dateGroup<={$dateTo}\n "); // Cache product types so call to findByPk() will trigger the registry ProductType::findMultipleByIds($objProducts->fetchEach('type')); $arrRaw = array(); $objProducts->reset(); // Prepare product data while ($objProducts->next()) { $arrAttributes = array(); $arrVariantAttributes = array(); $blnHasVariants = false; // Can't use it without a type if ($objProducts->type > 0 && ($objType = ProductType::findByPk($objProducts->type)) !== null) { /** @type ProductType $objType */ $arrAttributes = $objType->getAttributes(); $arrVariantAttributes = $objType->getVariantAttributes(); $blnHasVariants = $objType->hasVariants(); $product_type_name = $objType->name; } $arrOptions = array('name' => $objProducts->variant_name); // Use product title if name is not a variant attribute if ($blnHasVariants && !in_array('name', $arrVariantAttributes)) { $arrOptions['name'] = $objProducts->product_name; } $strSku = $blnHasVariants ? $objProducts->variant_sku : $objProducts->product_sku; if (in_array('sku', $arrAttributes) && $strSku != '') { $arrOptions['name'] = sprintf('%s <span style="color:#b3b3b3; padding-left:3px;">[%s]</span>', $arrOptions['name'], $strSku); } if ($blnVariants && $blnHasVariants) { if (in_array('sku', $arrVariantAttributes) && $objProducts->product_sku != '') { $arrOptions['name'] = sprintf('%s <span style="color:#b3b3b3; padding-left:3px;">[%s]</span>', $arrOptions['name'], $objProducts->product_sku); } foreach (deserialize($objProducts->product_configuration, true) as $strName => $strValue) { if (isset($GLOBALS['TL_DCA']['tl_iso_product']['fields'][$strName])) { $strValue = $GLOBALS['TL_DCA']['tl_iso_product']['fields'][$strName]['options'][$strValue] ? $GLOBALS['TL_DCA']['tl_iso_product']['fields'][$strName]['options'][$strValue] : $strValue; $strName = $GLOBALS['TL_DCA']['tl_iso_product']['fields'][$strName]['label'][0] ? $GLOBALS['TL_DCA']['tl_iso_product']['fields'][$strName]['label'][0] : $strName; } $arrOptions[] = '<span class="variant">' . $strName . ': ' . $strValue . '</span>'; } } $arrOptions['name'] = '<span class="product">' . $arrOptions['name'] . '</span>'; $arrRaw[$objProducts->product_id]['name'] = implode('<br>', $arrOptions); $arrRaw[$objProducts->product_id]['product_type_name'] = $product_type_name; $arrRaw[$objProducts->product_id][$objProducts->dateGroup] = (double) $arrRaw[$objProducts->product_id][$objProducts->dateGroup] + (double) $objProducts->total; $arrRaw[$objProducts->product_id][$objProducts->dateGroup . '_quantity'] = (int) $arrRaw[$objProducts->product_id][$objProducts->dateGroup . '_quantity'] + (int) $objProducts->quantity; $arrRaw[$objProducts->product_id]['total'] = (double) $arrRaw[$objProducts->product_id]['total'] + (double) $objProducts->total; $arrRaw[$objProducts->product_id]['quantity'] = (int) $arrRaw[$objProducts->product_id]['quantity'] + (int) $objProducts->quantity; } // Prepare columns $arrColumns = array(); for ($i = 0; $i < $intColumns; $i++) { $arrColumns[] = $period->getKey($intStart); $intStart = $period->getNext($intStart); } $arrFooter = array(); // Sort the data if ($arrSession[$this->name]['tl_sort'] == 'product_name') { usort($arrRaw, function ($a, $b) { return strcasecmp($a['name'], $b['name']); }); } else { usort($arrRaw, function ($a, $b) { return $a['total'] == $b['total'] ? 0 : ($a['total'] < $b['total'] ? 1 : -1); }); } // Generate data foreach ($arrRaw as $arrProduct) { $arrRow = array(array('value' => array($arrProduct['name'], sprintf('<span style="color:#b3b3b3;">[%s]</span>', $arrProduct['product_type_name'])))); $arrFooter[0] = array('value' => $GLOBALS['TL_LANG']['ISO_REPORT']['sums']); foreach ($arrColumns as $i => $column) { $arrRow[$i + 1] = array('value' => Isotope::formatPriceWithCurrency($arrProduct[$column]) . ($arrProduct[$column . '_quantity'] !== null ? '<br><span class="variant">' . Isotope::formatItemsString($arrProduct[$column . '_quantity']) . '</span>' : '')); $arrFooter[$i + 1] = array('total' => $arrFooter[$i + 1]['total'] + $arrProduct[$column], 'quantity' => $arrFooter[$i + 1]['quantity'] + $arrProduct[$column . '_quantity']); } $arrRow[$i + 2] = array('value' => Isotope::formatPriceWithCurrency($arrProduct['total']) . ($arrProduct['quantity'] !== null ? '<br><span class="variant">' . Isotope::formatItemsString($arrProduct['quantity']) . '</span>' : '')); $arrFooter[$i + 2] = array('total' => $arrFooter[$i + 2]['total'] + $arrProduct['total'], 'quantity' => $arrFooter[$i + 2]['quantity'] + $arrProduct['quantity']); $arrData['rows'][] = array('columns' => $arrRow); } for ($i = 1; $i < count($arrFooter); $i++) { $arrFooter[$i]['value'] = Isotope::formatPriceWithCurrency($arrFooter[$i]['total']) . '<br><span class="variant">' . Isotope::formatItemsString($arrFooter[$i]['quantity']) . '</span>'; unset($arrFooter[$i]['total']); } $arrData['footer'] = $arrFooter; $this->Template->data = $arrData; }
/** * Build palette for the current product type/variant */ public function buildPaletteString() { $this->loadDataContainer(Attribute::getTable()); if (\Input::get('act') == '' && \Input::get('key') == '' || \Input::get('act') == 'select') { return; } $arrTypes = array(); $arrFields =& $GLOBALS['TL_DCA']['tl_iso_product']['fields']; /** @var IsotopeAttribute[] $arrAttributes */ $arrAttributes =& $GLOBALS['TL_DCA']['tl_iso_product']['attributes']; $blnVariants = false; $act = \Input::get('act'); $blnSingleRecord = $act === 'edit' || $act === 'show'; if (\Input::get('id') > 0) { /** @type object $objProduct */ $objProduct = \Database::getInstance()->prepare("SELECT p1.pid, p1.type, p2.type AS parent_type FROM tl_iso_product p1 LEFT JOIN tl_iso_product p2 ON p1.pid=p2.id WHERE p1.id=?")->execute(\Input::get('id')); if ($objProduct->numRows) { $objType = ProductType::findByPk($objProduct->pid > 0 ? $objProduct->parent_type : $objProduct->type); $arrTypes = null === $objType ? array() : array($objType); if ($objProduct->pid > 0 || $act != 'edit' && $act != 'copyFallback' && $act != 'show') { $blnVariants = true; } } } else { $arrTypes = ProductType::findAllUsed() ?: array(); } /** @var \Isotope\Model\ProductType $objType */ foreach ($arrTypes as $objType) { // Enable advanced prices if ($blnSingleRecord && $objType->hasAdvancedPrices()) { $arrFields['prices']['exclude'] = $arrFields['price']['exclude']; $arrFields['prices']['attributes'] = $arrFields['price']['attributes']; $arrFields['price'] = $arrFields['prices']; } else { $GLOBALS['TL_DCA']['tl_iso_product']['config']['onversion_callback'][] = array('Isotope\\Backend\\Product\\Price', 'createVersion'); $GLOBALS['TL_DCA']['tl_iso_product']['config']['onrestore_callback'][] = array('Isotope\\Backend\\Product\\Price', 'restoreVersion'); } $arrInherit = array(); $arrPalette = array(); $arrLegends = array(); $arrLegendOrder = array(); $arrCanInherit = array(); if ($blnVariants) { $arrConfig = $objType->variant_attributes; $arrEnabled = $objType->getVariantAttributes(); $arrCanInherit = $objType->getAttributes(); } else { $arrConfig = $objType->attributes; $arrEnabled = $objType->getAttributes(); } // Go through each enabled field and build palette foreach ($arrFields as $name => $arrField) { if (in_array($name, $arrEnabled)) { if ($arrField['inputType'] == '') { continue; } // Variant fields can only be edited in variant mode if (null !== $arrAttributes[$name] && !$blnVariants && $arrAttributes[$name]->isVariantOption()) { continue; } // Field cannot be edited in variant if ($blnVariants && $arrAttributes[$name]->inherit) { continue; } $arrLegendOrder[$arrConfig[$name]['position']] = $arrConfig[$name]['legend']; $arrPalette[$arrConfig[$name]['legend']][$arrConfig[$name]['position']] = $name; // Apply product type attribute config if ($arrConfig[$name]['tl_class'] != '') { $arrFields[$name]['eval']['tl_class'] = $arrConfig[$name]['tl_class']; } if ($arrConfig[$name]['mandatory'] > 0) { $arrFields[$name]['eval']['mandatory'] = $arrConfig[$name]['mandatory'] == 1 ? false : true; } if ($blnVariants && in_array($name, $arrCanInherit) && null !== $arrAttributes[$name] && !$arrAttributes[$name]->isVariantOption() && !in_array($name, array('price', 'published', 'start', 'stop'))) { $arrInherit[$name] = Format::dcaLabel('tl_iso_product', $name); } } else { // Hide field from "show" option if (!isset($arrField['attributes']) || $arrField['inputType'] != '' && $name != 'inherit') { $arrFields[$name]['eval']['doNotShow'] = true; } } } ksort($arrLegendOrder); $arrLegendOrder = array_unique($arrLegendOrder); // Build foreach ($arrLegendOrder as $legend) { $fields = $arrPalette[$legend]; ksort($fields); $arrLegends[] = '{' . $legend . '},' . implode(',', $fields); } // Set inherit options $arrFields['inherit']['options'] = $arrInherit; // Add palettes $GLOBALS['TL_DCA']['tl_iso_product']['palettes'][$blnVariants ? 'default' : $objType->id] = ($blnVariants ? 'inherit,' : '') . implode(';', $arrLegends); } // Remove non-active fields from multi-selection if ($blnVariants && !$blnSingleRecord) { $arrInclude = empty($arrPalette) ? array() : call_user_func_array('array_merge', $arrPalette); foreach ($arrFields as $name => $config) { if ($arrFields[$name]['attributes']['legend'] != '' && !in_array($name, $arrInclude)) { $arrFields[$name]['exclude'] = true; } } } }
/** * Validate data and remove non-available attributes * * @param array $arrData * * @return $this */ public function setRow(array $arrData) { if ($arrData['pid'] > 0) { // Do not use the model, it would trigger setRow and generate too much // @deprecated use static::buildFindQuery once we drop BC support for buildQueryString /** @type object $objParent */ $objParent = \Database::getInstance()->prepare(static::buildQueryString(array('table' => static::$strTable, 'column' => 'id')))->execute($arrData['pid']); if (null === $objParent) { throw new \UnderflowException('Parent record of product variant ID ' . $arrData['id'] . ' not found'); } $this->setRow($objParent->row()); // Must be set before call to getInheritedFields() $this->arrData['id'] = $arrData['id']; $this->arrData['pid'] = $arrData['pid']; $this->arrData['inherit'] = $arrData['inherit']; // Set all variant attributes, except if they are inherited $arrFallbackFields = Attribute::getFetchFallbackFields(); $arrVariantFields = array_diff($this->getVariantAttributes(), $this->getInheritedFields()); foreach ($arrData as $attribute => $value) { if (in_array($attribute, $arrVariantFields) || $GLOBALS['TL_DCA']['tl_iso_product']['fields'][$attribute]['attributes']['legend'] == '' && !in_array(str_replace('_fallback', '', $attribute), $arrFallbackFields)) { $this->arrData[$attribute] = $arrData[$attribute]; if (in_array($attribute, $arrFallbackFields)) { $this->arrData[$attribute . '_fallback'] = $arrData[$attribute . '_fallback']; } } } // Make sure publishing settings match product and variant (see #1120) $this->arrData['published'] = $objParent->published ? $arrData['published'] : ''; $this->arrData['start'] = $objParent->start != '' && ($arrData['start'] == '' || $objParent->start > $arrData['start']) ? $objParent->start : $arrData['start']; $this->arrData['stop'] = $objParent->stop != '' && ($arrData['stop'] == '' || $objParent->stop < $arrData['stop']) ? $objParent->stop : $arrData['stop']; return $this; } // Empty cache $this->objPrice = false; $this->arrAttributes = null; $this->arrVariantAttributes = null; $this->arrVariantIds = null; $this->arrCategories = null; $this->arrRelated = array(); // Must initialize product type to have attributes etc. if (($this->arrRelated['type'] = ProductType::findByPk($arrData['type'])) === null) { throw new \UnderflowException('Product type for product ID ' . $arrData['id'] . ' not found'); } $this->strFormId = 'iso_product_' . $arrData['id']; // Remove attributes not in this product type foreach ($arrData as $attribute => $value) { if (!in_array($attribute, $this->getAttributes()) && !in_array($attribute, $this->getVariantAttributes()) && isset($GLOBALS['TL_DCA']['tl_iso_product']['fields'][$attribute]['attributes']['legend']) && $GLOBALS['TL_DCA']['tl_iso_product']['fields'][$attribute]['attributes']['legend'] != '' || in_array($attribute, Attribute::getVariantOptionFields())) { unset($arrData[$attribute]); } } return parent::setRow($arrData); }
public static function getOverridableStockProperty($strProperty, $objProduct) { // at first check for product and product type if ($objProduct->overrideStockShopConfig) { return $objProduct->{$strProperty}; } else { if (($objProductType = ProductType::findByPk($objProduct->type)) !== null && $objProductType->overrideStockShopConfig) { return $objProductType->{$strProperty}; } } // nothing returned? $objConfig = Isotope::getConfig(); // global $objPage; // // if ($objPage->iso_config) // { // $objConfig = Config::findByPk($objPage->iso_config); // } // defaultly return the value defined in the global config return $objConfig->{$strProperty}; }
public static function getProducts() { $objProducts = \Isotope\Model\Product::findPublished(); $arrProductTypeLabels = array(); $arrProducts = array(); while ($objProducts->next()) { // check for label cache if (isset($arrProductTypeLabels[$objProducts->type])) { $strProductTypeLabel = $arrProductTypeLabels[$objProducts->type]; } else { if (($objProductType = \Isotope\Model\ProductType::findByPk($objProducts->type)) !== null) { $strProductTypeLabel = $objProductType->name; $arrProductTypeLabels[$objProductType->id] = $objProductType->name; } } $arrProducts[$objProducts->id] = $strProductTypeLabel . ' - ' . $objProducts->name; } asort($arrProducts); return $arrProducts; }