/** * Returns true if the product is available * ALMOST THE SAME AS THE PARENT, EXCEPT WE DON'T CHECK FOR PRICE * * @param IsotopeProductCollection|\Isotope\Model\ProductCollection $objCollection * * @return bool */ public function isAvailableForCollection(IsotopeProductCollection $objCollection) { if ($objCollection->isLocked()) { return true; } if (BE_USER_LOGGED_IN !== true && !$this->isPublished()) { return false; } // Show to guests only if ($this->arrData['guests'] && $objCollection->member > 0 && BE_USER_LOGGED_IN !== true && !$this->arrData['protected']) { return false; } // Protected product if (BE_USER_LOGGED_IN !== true && $this->arrData['protected']) { if ($objCollection->member == 0) { return false; } $groups = deserialize($this->arrData['groups']); $memberGroups = deserialize($objCollection->getRelated('member')->groups); if (!is_array($groups) || empty($groups) || !is_array($memberGroups) || empty($memberGroups) || !count(array_intersect($groups, $memberGroups))) { return false; } } // Check that the product is in any page of the current site if (count(\Isotope\Frontend::getPagesInCurrentRoot($this->getCategories(), $objCollection->getRelated('member'))) == 0) { return false; } // Check if "advanced price" is available //if (null === $this->getPrice($objCollection) && (in_array('price', $this->getAttributes()) || $this->hasVariantPrices())) { // return false; //} return true; }
/** * Find advanced price for multiple product/variant IDs * * @param array $arrIds * @param IsotopeProductCollection|ProductCollection $objCollection * * @return \Model\Collection|null */ public static function findAdvancedByProductIdsAndCollection(array $arrIds, IsotopeProductCollection $objCollection) { $time = \Date::floorToMinute(); $arrGroups = static::getMemberGroups($objCollection->getRelated('member')); $objResult = \Database::getInstance()->query("\n SELECT *\n FROM (\n SELECT\n tl_iso_product_price.*,\n GROUP_CONCAT(tl_iso_product_pricetier.min) AS tier_keys,\n GROUP_CONCAT(tl_iso_product_pricetier.price) AS tier_values\n FROM tl_iso_product_price\n LEFT JOIN tl_iso_product_pricetier ON tl_iso_product_pricetier.pid = tl_iso_product_price.id\n WHERE\n config_id IN (" . (int) $objCollection->config_id . ",0) AND\n member_group IN(" . implode(',', $arrGroups) . ") AND\n (start='' OR start<'{$time}') AND\n (stop='' OR stop>'" . ($time + 60) . "') AND\n tl_iso_product_price.pid IN (" . implode(',', $arrIds) . ")\n GROUP BY tl_iso_product_price.id\n ORDER BY config_id DESC, " . \Database::getInstance()->findInSet('member_group', $arrGroups) . ", start DESC, stop DESC\n ) AS prices\n GROUP BY prices.pid\n "); if ($objResult->numRows) { return ProductPriceCollection::createFromDbResult($objResult, static::$strTable); } return null; }
/** * Create a new address for a product collection * * @param IsotopeProductCollection $objCollection * @param array|null $arrFill an array of member fields to inherit * @param bool $blnDefaultBilling * @param bool $blnDefaultShipping * * @return static */ public static function createForProductCollection(IsotopeProductCollection $objCollection, $arrFill = null, $blnDefaultBilling = false, $blnDefaultShipping = false) { $objAddress = new static(); $arrData = array('pid' => (int) $objCollection->id, 'ptable' => 'tl_iso_product_collection', 'tstamp' => time(), 'store_id' => (int) $objCollection->store_id, 'isDefaultBilling' => $blnDefaultBilling ? '1' : '', 'isDefaultShipping' => $blnDefaultShipping ? '1' : ''); if ($objCollection->member > 0 && !empty($arrFill) && is_array($arrFill) && ($objMember = \MemberModel::findByPk($objCollection->member)) !== null) { // Generate address data from tl_member, limit to fields enabled in the shop configuration $arrMember = array_intersect_key(array_merge($objMember->row(), array('street_1' => $objMember->street, 'subdivision' => strtoupper($objMember->country . '-' . $objMember->state))), array_flip($arrFill)); $arrData = array_merge($arrMember, $arrData); } if ($arrData['country'] == '' && ($objConfig = $objCollection->getRelated('config_id')) !== null) { if ($blnDefaultBilling) { $arrData['country'] = $objConfig->billing_country ?: $objConfig->country; } elseif ($blnDefaultShipping) { $arrData['country'] = $objConfig->shipping_country ?: $objConfig->country; } } $objAddress->setRow($arrData); return $objAddress; }
/** * Initialize a new collection and duplicate everything from the source * @param IsotopeProductCollection */ public static function createFromCollection(IsotopeProductCollection $objSource) { global $objPage; $objCollection = new static(); $objConfig = $objSource->getRelated('config_id'); if (null === $objConfig) { $objConfig = Isotope::getConfig(); } $objCollection->uniqid = uniqid(Haste::getInstance()->call('replaceInsertTags', array((string) $objConfig->orderPrefix, false)), true); $objCollection->source_collection_id = (int) $objSource->id; $objCollection->config_id = (int) $objConfig->id; $objCollection->store_id = (int) $objSource->store_id; $objCollection->member = (int) $objSource->member; $objCollection->language = (string) $GLOBALS['TL_LANGUAGE']; $objCollection->currency = (string) $objConfig->currency; $objCollection->pageId = (int) $objPage->id; $objCollection->setShippingMethod($objSource->getShippingMethod()); $objCollection->setPaymentMethod($objSource->getPaymentMethod()); $objCollection->setShippingAddress($objSource->getShippingAddress()); $objCollection->setBillingAddress($objSource->getBillingAddress()); $arrItemIds = $objCollection->copyItemsFrom($objSource); $arrSurchargeIds = $objCollection->copySurchargesFrom($objSource, $arrItemIds); $objCollection->updateDatabase(); // HOOK: order status has been updated if (isset($GLOBALS['ISO_HOOKS']['createFromProductCollection']) && is_array($GLOBALS['ISO_HOOKS']['createFromProductCollection'])) { foreach ($GLOBALS['ISO_HOOKS']['createFromProductCollection'] as $callback) { $objCallback = \System::importStatic($callback[0]); $objCallback->{$callback}[1]($objCollection, $objSource, $arrItemIds, $arrSurchargeIds); } } return $objCollection; }
/** * Initialize a new collection and duplicate everything from the source * * @param IsotopeProductCollection $objSource * * @return static */ public static function createFromCollection(IsotopeProductCollection $objSource) { $objCollection = new static(); $objConfig = $objSource->getRelated('config_id'); if (null === $objConfig) { $objConfig = Isotope::getConfig(); } $objCollection->source_collection_id = (int) $objSource->id; $objCollection->config_id = (int) $objConfig->id; $objCollection->store_id = (int) $objSource->store_id; $objCollection->member = (int) $objSource->member; $objCollection->setShippingMethod($objSource->getShippingMethod()); $objCollection->setPaymentMethod($objSource->getPaymentMethod()); $objCollection->setShippingAddress($objSource->getShippingAddress()); $objCollection->setBillingAddress($objSource->getBillingAddress()); $arrItemIds = $objCollection->copyItemsFrom($objSource); $objCollection->updateDatabase(); // HOOK: order status has been updated if (isset($GLOBALS['ISO_HOOKS']['createFromProductCollection']) && is_array($GLOBALS['ISO_HOOKS']['createFromProductCollection'])) { foreach ($GLOBALS['ISO_HOOKS']['createFromProductCollection'] as $callback) { $objCallback = \System::importStatic($callback[0]); $objCallback->{$callback}[1]($objCollection, $objSource, $arrItemIds); } } return $objCollection; }
/** * Find advanced price for multiple product/variant IDs * * @param array * @param IsotopeProductCollection * * @return \Model\Collection|null */ public static function findAdvancedByProductIdsAndCollection(array $arrIds, IsotopeProductCollection $objCollection) { $time = time(); $arrGroups = static::getMemberGroups($objCollection->getRelated('member')); $objResult = \Database::getInstance()->query("\n SELECT * FROM (\n SELECT *\n FROM " . static::$strTable . "\n WHERE\n config_id IN (" . (int) $objCollection->config_id . ",0) AND\n member_group IN(" . implode(',', $arrGroups) . ") AND\n (start='' OR start<{$time}) AND\n (stop='' OR stop>{$time}) AND\n pid IN (" . implode(',', $arrIds) . ")\n ORDER BY config_id DESC, " . \Database::getInstance()->findInSet('member_group', $arrGroups) . ", start DESC, stop DESC\n ) AS prices\n GROUP BY pid\n "); if ($objResult->numRows) { return \Isotope\Collection\ProductPrice::createFromDbResult($objResult, static::$strTable); } return null; }
/** * Generate and return document template * * @param IsotopeProductCollection $objCollection * @param array $arrTokens * * @return string */ protected function generateTemplate(IsotopeProductCollection $objCollection, array $arrTokens) { $objPage = \PageModel::findWithDetails($objCollection->page_id); $objTemplate = new \Isotope\Template($this->documentTpl); $objTemplate->setData($this->arrData); $objTemplate->title = \StringUtil::parseSimpleTokens($this->documentTitle, $arrTokens); $objTemplate->collection = $objCollection; $objTemplate->config = $objCollection->getRelated('config_id'); $objTemplate->page = $objPage; $objTemplate->dateFormat = $objPage->dateFormat ?: $GLOBALS['TL_CONFIG']['dateFormat']; $objTemplate->timeFormat = $objPage->timeFormat ?: $GLOBALS['TL_CONFIG']['timeFormat']; $objTemplate->datimFormat = $objPage->datimFormat ?: $GLOBALS['TL_CONFIG']['datimFormat']; // Render the collection $objCollectionTemplate = new \Isotope\Template($this->collectionTpl); $objCollection->addToTemplate($objCollectionTemplate, array('gallery' => $this->gallery, 'sorting' => $objCollection->getItemsSortingCallable($this->orderCollectionBy))); $objTemplate->products = $objCollectionTemplate->parse(); // !HOOK: customize the document template if (isset($GLOBALS['ISO_HOOKS']['generateDocumentTemplate']) && is_array($GLOBALS['ISO_HOOKS']['generateDocumentTemplate'])) { foreach ($GLOBALS['ISO_HOOKS']['generateDocumentTemplate'] as $callback) { \System::importStatic($callback[0])->{$callback}[1]($objTemplate, $objCollection, $this); } } // Generate template and fix PDF issues, see Contao's ModuleArticle $strBuffer = Haste::getInstance()->call('replaceInsertTags', array($objTemplate->parse(), false)); $strBuffer = html_entity_decode($strBuffer, ENT_QUOTES, $GLOBALS['TL_CONFIG']['characterSet']); $strBuffer = \Controller::convertRelativeUrls($strBuffer, '', true); // Remove form elements and JavaScript links $arrSearch = array('@<form.*</form>@Us', '@<a [^>]*href="[^"]*javascript:[^>]+>.*</a>@Us'); $strBuffer = preg_replace($arrSearch, '', $strBuffer); // URL decode image paths (see contao/core#6411) // Make image paths absolute $strBuffer = preg_replace_callback('@(src=")([^"]+)(")@', function ($args) { if (preg_match('@^(http://|https://)@', $args[2])) { return $args[2]; } return $args[1] . TL_ROOT . '/' . rawurldecode($args[2]) . $args[3]; }, $strBuffer); // Handle line breaks in preformatted text $strBuffer = preg_replace_callback('@(<pre.*</pre>)@Us', 'nl2br_callback', $strBuffer); // Default PDF export using TCPDF $arrSearch = array('@<span style="text-decoration: ?underline;?">(.*)</span>@Us', '@(<img[^>]+>)@', '@(<div[^>]+block[^>]+>)@', '@[\\n\\r\\t]+@', '@<br( /)?><div class="mod_article@', '@href="([^"]+)(pdf=[0-9]*(&|&)?)([^"]*)"@'); $arrReplace = array('<u>$1</u>', '<br>$1', '<br>$1', ' ', '<div class="mod_article', 'href="$1$4"'); $strBuffer = preg_replace($arrSearch, $arrReplace, $strBuffer); return $strBuffer; }
/** * Add cart rules to surcharges */ public function findSurcharges(IsotopeProductCollection $objCollection) { $objCart = $objCollection; // The checkout review pages shows an order, but we need the cart // Only the cart contains coupons etc. if ($objCollection instanceof Order) { $objCart = $objCollection->getRelated('source_collection_id'); } // Rules should only be applied to Cart, not any other product collection if (!$objCart instanceof Cart) { return array(); } $arrSurcharges = array(); $objRules = Rule::findForCart(); if (null !== $objRules) { while ($objRules->next()) { $objSurcharge = RuleSurcharge::createForRuleInCollection($objRules->current(), $objCollection); if (null !== $objSurcharge) { $arrSurcharges[] = $objSurcharge; } } } $arrCoupons = deserialize($objCart->coupons); if (!empty($arrCoupons) && is_array($arrCoupons)) { $arrDropped = array(); foreach ($arrCoupons as $code) { $objRule = Rule::findOneByCouponCode($code, $objCollection->getItems()); if (null === $objRule) { $arrDropped[] = $code; } else { // cart rules should total all eligible products for the cart discount and apply the discount to that amount rather than individual products. $objSurcharge = RuleSurcharge::createForRuleInCollection($objRule, $objCollection); if (null !== $objSurcharge) { $arrSurcharges[] = $objSurcharge; } } } if (!empty($arrDropped)) { // @todo show dropped coupons $arrCoupons = array_diff($arrCoupons, $arrDropped); \Database::getInstance()->query("UPDATE tl_iso_product_collection SET coupons='" . serialize($arrCoupons) . "' WHERE id=" . (int) Isotope::getCart()->id); } } return $arrSurcharges; }
/** * Process post-sale requestion from the PSP payment server. * @param IsotopeProductCollection */ public function processPostsale(IsotopeProductCollection $objOrder) { if (!$this->validateSHASign()) { \System::log('Received invalid postsale data for order ID "' . $objOrder->id . '"', __METHOD__, TL_ERROR); return false; } // Validate payment data if ($objOrder->currency != $this->getRequestData('currency') || $objOrder->getTotal() != $this->getRequestData('amount')) { \System::log('Postsale checkout manipulation in payment for Order ID ' . $objOrder->id . '!', __METHOD__, TL_ERROR); return false; } // Validate payment status switch ($this->getRequestData('STATUS')) { case 9: // Zahlung beantragt (Authorize & Capture) $objOrder->date_paid = time(); // no break // no break case 5: // Genehmigt (Authorize ohne Capture) $intStatus = $this->new_order_status; break; case 41: // Unbekannter Wartezustand // Unbekannter Wartezustand case 51: // Genehmigung im Wartezustand // Genehmigung im Wartezustand case 91: // Zahlung im Wartezustand // Zahlung im Wartezustand case 52: // Genehmigung nicht bekannt // Genehmigung nicht bekannt case 92: // Zahlung unsicher if (($objConfig = $objOrder->getRelated('config_id')) === null) { $this->log('Config for Order ID ' . $objOrder->id . ' not found', __METHOD__, TL_ERROR); return false; } $intStatus = $objConfig->orderstatus_error; break; case 0: // Ungültig / Unvollständig // Ungültig / Unvollständig case 1: // Zahlungsvorgang abgebrochen // Zahlungsvorgang abgebrochen case 2: // Genehmigung verweigert // Genehmigung verweigert case 4: // Gespeichert // Gespeichert case 93: // Bezahlung verweigert // Bezahlung verweigert default: return false; } if (!$objOrder->checkout()) { \System::log('Post-Sale checkout for Order ID "' . $objOrder->id . '" failed', __METHOD__, TL_ERROR); return false; } $objOrder->updateOrderStatus($intStatus); $objOrder->save(); return true; }