/** * Fill the object's arrProducts array * * @param array|null $arrCacheIds * * @return array */ protected function findProducts($arrCacheIds = null) { $t = Product::getTable(); $arrColumns = array(); $arrCategories = $this->findCategories(); $arrProductIds = \Database::getInstance()->query("\n SELECT pid\n FROM tl_iso_product_category\n WHERE page_id IN (" . implode(',', $arrCategories) . ")\n ")->fetchEach('pid'); $arrTypes = \Database::getInstance()->query("SELECT id FROM tl_iso_producttype WHERE variants='1'")->fetchEach('id'); if (empty($arrProductIds)) { return array(); } $queryBuilder = new FilterQueryBuilder(Isotope::getRequestCache()->getFiltersForModules($this->iso_filterModules)); $arrColumns[] = "(\n ({$t}.id IN (" . implode(',', $arrProductIds) . ") AND {$t}.type NOT IN (" . implode(',', $arrTypes) . "))\n OR {$t}.pid IN (" . implode(',', $arrProductIds) . ")\n )"; if (!empty($arrCacheIds) && is_array($arrCacheIds)) { $arrColumns[] = Product::getTable() . ".id IN (" . implode(',', $arrCacheIds) . ")"; } // Apply new/old product filter if ($this->iso_newFilter == 'show_new') { $arrColumns[] = Product::getTable() . ".dateAdded>=" . Isotope::getConfig()->getNewProductLimit(); } elseif ($this->iso_newFilter == 'show_old') { $arrColumns[] = Product::getTable() . ".dateAdded<" . Isotope::getConfig()->getNewProductLimit(); } if ($this->iso_list_where != '') { $arrColumns[] = $this->iso_list_where; } if ($queryBuilder->hasSqlCondition()) { $arrColumns[] = $queryBuilder->getSqlWhere(); } $arrSorting = Isotope::getRequestCache()->getSortingsForModules($this->iso_filterModules); if (empty($arrSorting) && $this->iso_listingSortField != '') { $direction = $this->iso_listingSortDirection == 'DESC' ? Sort::descending() : Sort::ascending(); $arrSorting[$this->iso_listingSortField] = $direction; } $objProducts = Product::findAvailableBy($arrColumns, $queryBuilder->getSqlValues(), array('order' => 'c.sorting', 'filters' => $queryBuilder->getFilters(), 'sorting' => $arrSorting)); return null === $objProducts ? array() : $objProducts->getModels(); }
/** * Check the cart currency for ePay support * * @return bool */ public function isAvailable() { if (!Currency::isSupported(Isotope::getConfig()->currency)) { return false; } return parent::isAvailable(); }
/** * sofortueberweisung.de only supports these currencies * @return true */ public function isAvailable() { if (!in_array(Isotope::getConfig()->currency, array('EUR', 'CHF', 'GBP'))) { return false; } return parent::isAvailable(); }
/** * Check the cart currency for ePay support * * @return bool */ public function isAvailable() { if (!static::supportsCurrency(Isotope::getConfig()->currency)) { return false; } return parent::isAvailable(); }
/** * Paybyway only supports EUR currency * @return bool */ public function isAvailable() { $objConfig = Isotope::getConfig(); if (null === $objConfig || $objConfig->currency != 'EUR') { return false; } return parent::isAvailable(); }
/** * Compile the module * @return void */ protected function compile() { $arrConfigs = array(); $objConfigs = Config::findMultipleByIds($this->iso_config_ids); if (null !== $objConfigs) { while ($objConfigs->next()) { $arrConfigs[] = array('config' => $objConfigs->current(), 'label' => $objConfigs->current()->getLabel(), 'active' => Isotope::getConfig()->id == $objConfigs->id ? true : false, 'href' => \Environment::get('request') . (strpos(\Environment::get('request'), '?') === false ? '?' : '&') . 'config=' . $objConfigs->id); } } \Haste\Generator\RowClass::withKey('class')->addFirstLast()->applyTo($arrConfigs); $this->Template->configs = $arrConfigs; }
/** * Limit the member countries to the selection in store config * @param string */ public function limitCountries($strTable) { if ($strTable != 'tl_member' || !Isotope::getConfig()->limitMemberCountries) { return; } $arrCountries = array_unique(array_merge(Isotope::getConfig()->getBillingCountries(), Isotope::getConfig()->getShippingCountries())); $arrCountries = array_intersect_key($GLOBALS['TL_DCA']['tl_member']['fields']['country']['options'], array_flip($arrCountries)); $GLOBALS['TL_DCA']['tl_member']['fields']['country']['options'] = $arrCountries; if (count($arrCountries) == 1) { $arrCountryCodes = array_keys($arrCountries); $GLOBALS['TL_DCA']['tl_member']['fields']['country']['default'] = $arrCountryCodes[0]; } }
/** * Calculate a price, removing tax if included but not applicable * * @param float $fltPrice * @param array $arrAddresses * * @return float */ public function calculatePrice($fltPrice, array $arrAddresses = null) { switch (Isotope::getConfig()->getPriceDisplay()) { case Config::PRICE_DISPLAY_NET: return $this->calculateNetPrice($fltPrice); case Config::PRICE_DISPLAY_GROSS: return $this->calculateGrossPrice($fltPrice, $arrAddresses); case Config::PRICE_DISPLAY_FIXED: return $fltPrice; case Config::PRICE_DISPLAY_LEGACY: default: return $this->calculateLegacyPrice($fltPrice, $arrAddresses); } }
/** * SEPA only supports these currencies * @return true */ public function isAvailable() { if (!in_array(Isotope::getConfig()->currency, array('EUR'))) { return false; } if (!FE_USER_LOGGED_IN) { return false; } else { $user = \FrontendUser::getInstance(); if (!isset($user->iso_sepa_active) || $user->iso_sepa_active != "1") { return false; } } return parent::isAvailable(); }
/** * Generate the order label and return it as string * @param array * @param string * @return string */ public function getOrderLabel($row, $label, \DataContainer $dc, $args) { /** @var Order $objOrder */ $objOrder = Order::findByPk($row['id']); if (null === $objOrder) { return $args; } // Override system to correctly format currencies etc Isotope::setConfig($objOrder->getRelated('config_id')); $objAddress = $objOrder->getBillingAddress(); if (null !== $objAddress) { $arrTokens = $objAddress->getTokens(Isotope::getConfig()->getBillingFieldsConfig()); $args[2] = $arrTokens['hcard_fn']; } $args[3] = Isotope::formatPriceWithCurrency($row['grandTotal']); /** @var \Isotope\Model\OrderStatus $objStatus */ if (($objStatus = $objOrder->getRelated('order_status')) !== null) { $args[4] = '<span style="' . $objStatus->getColorStyles() . '">' . $objOrder->getStatusLabel() . '</span>'; } else { $args[4] = '<span>' . $objOrder->getStatusLabel() . '</span>'; } return $args; }
/** * 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; }
/** * Generate unique order ID including the order prefix * * @return string */ protected function generateUniqueId() { if ($this->arrData['uniqid'] != '') { return $this->arrData['uniqid']; } $objConfig = $this->getRelated('config_id'); if (null === $objConfig) { $objConfig = Isotope::getConfig(); } return uniqid(Haste::getInstance()->call('replaceInsertTags', array((string) $objConfig->orderPrefix, false)), true); }
/** * Get error messages for the cart * @return array */ public function getErrors() { $arrErrors = parent::getErrors(); if (Isotope::getConfig()->cartMinSubtotal > 0 && Isotope::getConfig()->cartMinSubtotal > $this->getSubtotal()) { $arrErrors[] = sprintf($GLOBALS['TL_LANG']['ERR']['cartMinSubtotal'], Isotope::formatPriceWithCurrency(Isotope::getConfig()->cartMinSubtotal)); } return $arrErrors; }
/** * Returns the timestamp when the product cache expires * @return int */ protected function getProductCacheExpiration() { $time = time(); // Find timestamp when the next product becomes available $expires = (int) \Database::getInstance()->execute("SELECT MIN(start) AS expires FROM tl_iso_product WHERE start>{$time}")->expires; // Find if ($this->iso_newFilter == 'show_new' || $this->iso_newFilter == 'show_old') { $added = \Database::getInstance()->execute("SELECT MIN(dateAdded) FROM tl_iso_product WHERE dateAdded>" . Isotope::getConfig()->getNewProductLimit()); if ($added < $expires) { $expires = $added; } } return $expires; }
/** * Get "add to total" state for tax rate * * @param bool $default The legacy state (if tax was included in backend price) * * @return bool */ private static function getTaxAddState($default) { switch (Isotope::getConfig()->getPriceDisplay()) { case Config::PRICE_DISPLAY_NET: return true; case Config::PRICE_DISPLAY_GROSS: case Config::PRICE_DISPLAY_FIXED: return false; case Config::PRICE_DISPLAY_LEGACY: default: return $default; } }
/** * Callback for checkout Hook. Transfer active rules to usage table. */ public function writeRuleUsages($objOrder) { $objCart = Cart::findByPk($objOrder->source_collection_id); $objRules = Rule::findActiveWitoutCoupons(); $arrRules = null === $objRules ? array() : $objRules->fetchEach('id'); $arrCoupons = deserialize($objCart->coupons); if (is_array($arrCoupons) && !empty($arrCoupons)) { $blnError = false; foreach ($arrCoupons as $k => $code) { $objRule = Rule::findOneByCouponCode($code, $objCart->getItems()); if (null === $objRule) { Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['couponCodeDropped'], $code)); unset($arrCoupons[$k]); $blnError = true; } else { $arrRules[] = $objRule->id; } } if ($blnError) { $objCart->coupons = $arrCoupons; return false; } } if (!empty($arrRules)) { $time = time(); \Database::getInstance()->query("INSERT INTO tl_iso_rule_usage (pid,tstamp,order_id,config_id,member_id) VALUES (" . implode(", {$time}, {$objOrder->id}, " . (int) Isotope::getConfig()->id . ", {$objOrder->member}), (", $arrRules) . ", {$time}, {$objOrder->id}, " . (int) Isotope::getConfig()->id . ", {$objOrder->member})"); } return true; }
/** * Fetch rules */ protected static function findByConditions($arrProcedures, $arrValues = array(), $arrProducts = null, $blnIncludeVariants = false, $arrAttributeData = array()) { // Only enabled rules $arrProcedures[] = "enabled='1'"; // Date & Time restrictions $date = date('Y-m-d'); $time = date('H:i:s'); $arrProcedures[] = "(startDate='' OR startDate <= UNIX_TIMESTAMP('{$date}'))"; $arrProcedures[] = "(endDate='' OR endDate >= UNIX_TIMESTAMP('{$date}'))"; $arrProcedures[] = "(startTime='' OR startTime <= UNIX_TIMESTAMP('1970-01-01 {$time}'))"; $arrProcedures[] = "(endTime='' OR endTime >= UNIX_TIMESTAMP('1970-01-01 {$time}'))"; // Limits $arrProcedures[] = "(limitPerConfig=0 OR limitPerConfig>(SELECT COUNT(*) FROM tl_iso_rule_usage WHERE pid=r.id AND config_id=" . (int) Isotope::getConfig()->id . " AND order_id NOT IN (SELECT id FROM tl_iso_product_collection WHERE type='order' AND source_collection_id=" . (int) Isotope::getCart()->id . ")))"; if (Isotope::getCart()->member > 0) { $arrProcedures[] = "(limitPerMember=0 OR limitPerMember>(SELECT COUNT(*) FROM tl_iso_rule_usage WHERE pid=r.id AND member_id=" . (int) \FrontendUser::getInstance()->id . " AND order_id NOT IN (SELECT id FROM tl_iso_product_collection WHERE type='order' AND source_collection_id=" . (int) Isotope::getCart()->id . ")))"; } // Store config restrictions $arrProcedures[] = "(configRestrictions=''\n OR (configRestrictions='1' AND configCondition='1' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='configs' AND object_id=" . (int) Isotope::getConfig()->id . ")>0)\n OR (configRestrictions='1' AND configCondition='0' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='configs' AND object_id=" . (int) Isotope::getConfig()->id . ")=0))"; // Member restrictions if (Isotope::getCart()->member > 0) { $arrGroups = array_map('intval', deserialize(\FrontendUser::getInstance()->groups, true)); $arrProcedures[] = "(memberRestrictions='none'\n OR (memberRestrictions='guests' AND memberCondition='0')\n OR (memberRestrictions='members' AND memberCondition='1' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='members' AND object_id=" . (int) \FrontendUser::getInstance()->id . ")>0)\n OR (memberRestrictions='members' AND memberCondition='0' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='members' AND object_id=" . (int) \FrontendUser::getInstance()->id . ")=0)\n " . (!empty($arrGroups) ? "\n OR (memberRestrictions='groups' AND memberCondition='1' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='groups' AND object_id IN (" . implode(',', $arrGroups) . "))>0)\n OR (memberRestrictions='groups' AND memberCondition='0' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='groups' AND object_id IN (" . implode(',', $arrGroups) . "))=0)" : '') . ")"; } else { $arrProcedures[] = "(memberRestrictions='none' OR (memberRestrictions='guests' AND memberCondition='1'))"; } // Product restrictions if (!is_array($arrProducts)) { $arrProducts = Isotope::getCart()->getItems(); } if (!empty($arrProducts)) { $arrProductIds = array(0); $arrVariantIds = array(0); $arrAttributes = array(0); $arrTypes = array(0); // Prepare product attribute condition $objAttributeRules = \Database::getInstance()->execute("SELECT * FROM " . static::$strTable . " WHERE enabled='1' AND productRestrictions='attribute' AND attributeName!='' GROUP BY attributeName, attributeCondition"); while ($objAttributeRules->next()) { $arrAttributes[] = array('attribute' => $objAttributeRules->attributeName, 'condition' => $objAttributeRules->attributeCondition, 'values' => array()); } foreach ($arrProducts as $objProduct) { if ($objProduct instanceof ProductCollectionItem) { if (!$objProduct->hasProduct()) { continue; } $objProduct = $objProduct->getProduct(); } $arrProductIds[] = (int) $objProduct->getProductId(); $arrVariantIds[] = (int) $objProduct->{$objProduct->getPk()}; $arrTypes[] = (int) $objProduct->type; if ($objProduct->isVariant()) { $arrVariantIds[] = (int) $objProduct->pid; } if ($blnIncludeVariants && $objProduct->hasVariants()) { $arrVariantIds = array_merge($arrVariantIds, $objProduct->getVariantIds()); } $arrOptions = $objProduct->getOptions(); foreach ($arrAttributes as $k => $restriction) { $varValue = null; if (isset($arrAttributeData[$restriction['attribute']])) { $varValue = $arrAttributeData[$restriction['attribute']]; } elseif (isset($arrOptions[$restriction['attribute']])) { $varValue = $arrOptions[$restriction['attribute']]; } else { $varValue = $objProduct->{$restriction['attribute']}; } if (!is_null($varValue)) { $arrAttributes[$k]['values'][] = is_array($varValue) ? serialize($varValue) : $varValue; } } } $arrProductIds = array_unique($arrProductIds); $arrVariantIds = array_unique($arrVariantIds); $arrRestrictions = array("productRestrictions='none'"); $arrRestrictions[] = "(productRestrictions='producttypes' AND productCondition='1' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='producttypes' AND object_id IN (" . implode(',', $arrTypes) . "))>0)"; $arrRestrictions[] = "(productRestrictions='producttypes' AND productCondition='0' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='producttypes' AND object_id IN (" . implode(',', $arrTypes) . "))=0)"; $arrRestrictions[] = "(productRestrictions='products' AND productCondition='1' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='products' AND object_id IN (" . implode(',', $arrProductIds) . "))>0)"; $arrRestrictions[] = "(productRestrictions='products' AND productCondition='0' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='products' AND object_id IN (" . implode(',', $arrProductIds) . "))=0)"; $arrRestrictions[] = "(productRestrictions='variants' AND productCondition='1' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='variants' AND object_id IN (" . implode(',', $arrVariantIds) . "))>0)"; $arrRestrictions[] = "(productRestrictions='variants' AND productCondition='0' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='variants' AND object_id IN (" . implode(',', $arrVariantIds) . "))=0)"; $arrRestrictions[] = "(productRestrictions='pages' AND productCondition='1' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='pages' AND object_id IN (SELECT page_id FROM " . \Isotope\Model\ProductCategory::getTable() . " WHERE pid IN (" . implode(',', $arrProductIds) . ")))>0)"; $arrRestrictions[] = "(productRestrictions='pages' AND productCondition='0' AND (SELECT COUNT(*) FROM tl_iso_rule_restriction WHERE pid=r.id AND type='pages' AND object_id IN (SELECT page_id FROM " . \Isotope\Model\ProductCategory::getTable() . " WHERE pid IN (" . implode(',', $arrProductIds) . ")))=0)"; foreach ($arrAttributes as $restriction) { if (empty($restriction['values'])) { continue; } $strRestriction = "(productRestrictions='attribute' AND attributeName='" . $restriction['attribute'] . "' AND attributeCondition='" . $restriction['condition'] . "' AND "; switch ($restriction['condition']) { case 'eq': case 'neq': $strRestriction .= "attributeValue" . ($restriction['condition'] == 'neq' ? " NOT" : '') . " IN ('" . implode("','", array_map('mysql_real_escape_string', $restriction['values'])) . "')"; break; case 'lt': case 'gt': case 'elt': case 'egt': $arrOR = array(); foreach ($restriction['values'] as $value) { $arrOR[] = "attributeValue" . ($restriction['condition'] == 'lt' || $restriction['condition'] == 'elt' ? '>' : '<') . ($restriction['condition'] == 'elt' || $restriction['condition'] == 'egt' ? '=' : '') . '?'; $arrValues[] = $value; } $strRestriction .= '(' . implode(' OR ', $arrOR) . ')'; break; case 'starts': case 'ends': case 'contains': $arrOR = array(); foreach ($restriction['values'] as $value) { $arrOR[] = "? LIKE CONCAT(" . ($restriction['condition'] == 'ends' || $restriction['condition'] == 'contains' ? "'%', " : '') . "attributeValue" . ($restriction['condition'] == 'starts' || $restriction['condition'] == 'contains' ? ", '%'" : '') . ")"; $arrValues[] = $value; } $strRestriction .= '(' . implode(' OR ', $arrOR) . ')'; break; default: throw new \InvalidArgumentException('Unknown rule condition "' . $restriction['condition'] . '"'); } $arrRestrictions[] = $strRestriction . ')'; } $arrProcedures[] = '(' . implode(' OR ', $arrRestrictions) . ')'; } $objResult = \Database::getInstance()->prepare("SELECT * FROM " . static::$strTable . " r WHERE " . implode(' AND ', $arrProcedures))->execute($arrValues); if ($objResult->numRows) { return \Model\Collection::createFromDbResult($objResult, static::$strTable); } return null; }
/** * Build a shipment from an IsotopeCollection * @param IsotopeProductCollection * @return stdClass */ protected function buildShipmentFromCollection(IsotopeProductCollection $objCollection) { //Get the Iso Config $Config = Isotope::getConfig(); //Create the shipment $Shipment = new Ups_Shipment(); // Create the service $Service = new Ups_Service(); $Service->setCode($this->ups_enabledService); $Service->setDescription($GLOBALS['TL_LANG']['tl_iso_shipping']['ups_service'][$this->ups_enabledService]); $Shipment->setService($Service); //Build Shipper information $Shipper = new Ups_Shipper(); $Shipper->setShipperNumber($Config->UpsAccountNumber); //ShipFrom Address $ShipFromAddress = static::buildAddress($Config); //Assign to Shipper $Shipper->setAddress($ShipFromAddress); $Shipment->setShipper($Shipper); //ShipFrom Object $ShipFrom = new Ups_ShipFrom(); $ShipFrom->setAddress($ShipFromAddress); $ShipFrom->setCompanyName($Config->company); $Shipment->setShipFrom($ShipFrom); //ShipTo Address $objShippingAddress = $objCollection->getShippingAddress(); $ShipToAddress = static::buildAddress($objShippingAddress); //ShipTo Object $ShipTo = new Ups_ShipTo(); $ShipTo->setAddress($ShipToAddress); $ShipTo->setAttentionName($objShippingAddress->firstname . ' ' . $objShippingAddress->lastname); $Shipment->setShipTo($ShipTo); $Shipment->setPackages($this->buildPackages($objCollection)); return $Shipment; }
/** * 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; }
/** * Return true or false depending on availability of the payment method * @return bool * @todo must check availability for a specific product collection (and not hardcoded to the current cart) */ public function isAvailable() { if (!$this->enabled && BE_USER_LOGGED_IN !== true) { return false; } if ($this->guests && FE_USER_LOGGED_IN === true || $this->protected && FE_USER_LOGGED_IN !== true) { return false; } if ($this->protected) { $arrGroups = deserialize($this->groups); if (!is_array($arrGroups) || empty($arrGroups) || !count(array_intersect($arrGroups, \FrontendUser::getInstance()->groups))) { return false; } } if ($this->minimum_total > 0 && $this->minimum_total > Isotope::getCart()->getSubtotal() || $this->maximum_total > 0 && $this->maximum_total < Isotope::getCart()->getSubtotal()) { return false; } $arrConfigs = deserialize($this->config_ids); if (is_array($arrConfigs) && !empty($arrConfigs) && !in_array(Isotope::getConfig()->id, $arrConfigs)) { return false; } $arrCountries = deserialize($this->countries); if (is_array($arrCountries) && !empty($arrCountries) && !in_array(Isotope::getCart()->getBillingAddress()->country, $arrCountries)) { return false; } $arrShippings = deserialize($this->shipping_modules); if (is_array($arrShippings) && !empty($arrShippings) && (!Isotope::getCart()->hasShipping() && !in_array(-1, $arrShippings) || Isotope::getCart()->hasShipping() && !in_array(Isotope::getCart()->getShippingMethod()->id, $arrShippings))) { return false; } $arrConfigTypes = deserialize($this->product_types); if (is_array($arrConfigTypes) && !empty($arrConfigTypes)) { $arrItems = Isotope::getCart()->getItems(); $arrItemTypes = array(); foreach ($arrItems as $objItem) { if ($objItem->hasProduct()) { $arrItemTypes[] = $objItem->getProduct()->type; } elseif ($this->product_types_condition == 'onlyAvailable') { // If one product in cart is not of given type, shipping method is not available return false; } } $arrItemTypes = array_unique($arrItemTypes); switch ($this->product_types_condition) { case 'onlyAvailable': if (count(array_diff($arrItemTypes, $arrConfigTypes)) > 0) { return false; } break; case 'oneAvailable': if (count(array_intersect($arrConfigTypes, $arrItemTypes)) == 0) { return false; } break; case 'allAvailable': if (count(array_intersect($arrConfigTypes, $arrItemTypes)) != count($arrConfigTypes)) { return false; } break; default: throw new \UnexpectedValueException('Unknown product type condition "' . $this->product_types_condition . '"'); } } return true; }
/** * Determine if this tax rate is applicable * * @param float $fltPrice * @param array $arrAddresses * * @return bool */ public function isApplicable($fltPrice, $arrAddresses) { // Tax rate is limited to another store config if ($this->config > 0 && $this->config != Isotope::getConfig()->id) { return false; } // Tax rate is for guests only if ($this->guests && FE_USER_LOGGED_IN === true && !$this->protected) { return false; } // Tax rate is protected but no member is logged in if ($this->protected && FE_USER_LOGGED_IN !== true && !$this->guests) { return false; } // Tax rate is protected and member logged in, check member groups if ($this->protected && FE_USER_LOGGED_IN === true) { $groups = deserialize($this->groups); if (!is_array($groups) || empty($groups) || !count(array_intersect($groups, \FrontendUser::getInstance()->groups))) { return false; } } // !HOOK: use tax rate if (isset($GLOBALS['ISO_HOOKS']['useTaxRate']) && is_array($GLOBALS['ISO_HOOKS']['useTaxRate'])) { foreach ($GLOBALS['ISO_HOOKS']['useTaxRate'] as $callback) { $objCallback = \System::importStatic($callback[0]); $varValue = $objCallback->{$callback}[1]($this, $fltPrice, $arrAddresses); if ($varValue !== true) { return false; } } } $arrAddress = deserialize($this->address); if (!empty($arrAddress) && is_array($arrAddress)) { foreach ($arrAddresses as $name => $objAddress) { if (!in_array($name, $arrAddress)) { continue; } if ($this->countries != '' && !in_array($objAddress->country, trimsplit(',', $this->countries))) { continue; } if ($this->subdivisions != '' && !in_array($objAddress->subdivision, trimsplit(',', $this->subdivisions))) { continue; } // Check if address has a valid postal code if ($this->postalCodes != '') { $arrCodes = \Isotope\Frontend::parsePostalCodes($this->postalCodes); if (!in_array($objAddress->postal, $arrCodes)) { continue; } } $arrPrice = deserialize($this->amount); if (is_array($arrPrice) && !empty($arrPrice) && strlen($arrPrice[0])) { if (strlen($arrPrice[1])) { if ($arrPrice[0] > $fltPrice || $arrPrice[1] < $fltPrice) { continue; } } else { if ($arrPrice[0] != $fltPrice) { continue; } } } if ($this->exemptOnValidVAT) { $validators = deserialize(Isotope::getConfig()->vatNoValidators); if (!empty($validators) && is_array($validators)) { foreach ($validators as $type) { /** @type IsotopeVatNoValidator $service */ $service = new $GLOBALS['ISO_VAT'][$type](); if ($service->exemptTax($objAddress, $this)) { continue 2; } } } } // This address is valid, otherwise one of the check would have skipped this (continue) return true; } // No address has passed all checks and returned true return false; } // Addresses are not checked at all, return true return true; }
/** * Sets up the API Object * * @access public */ public function __construct() { /** Set the Keys on the Object **/ $this->access_key = Isotope::getConfig()->FedExAccessKey; /** Set the username and password on the Object **/ $this->password = Isotope::getConfig()->FedExPassword; $this->username = Isotope::getConfig()->FedExUsername; $this->accountNumber = Isotope::getConfig()->FedExAccountNumber; $this->meterNumber = Isotope::getConfig()->FedExMeterNumber; $this->server = 'https://gateway' . (Isotope::getConfig()->FedExMode == 'test' ? "beta" : "") . '.fedex.com/xml/'; }
private function countProductsForFilter(array $filters) { $arrColumns = array(); $arrCategories = $this->findCategories(); $queryBuilder = new FilterQueryBuilder($filters); $arrColumns[] = "c.page_id IN (" . implode(',', $arrCategories) . ")"; // Apply new/old product filter if ($this->iso_newFilter == self::FILTER_NEW) { $arrColumns[] = Product::getTable() . ".dateAdded>=" . Isotope::getConfig()->getNewProductLimit(); } elseif ($this->iso_newFilter == self::FILTER_OLD) { $arrColumns[] = Product::getTable() . ".dateAdded<" . Isotope::getConfig()->getNewProductLimit(); } if ($this->iso_list_where != '') { $arrColumns[] = $this->iso_list_where; } if ($queryBuilder->hasSqlCondition()) { $arrColumns[] = $queryBuilder->getSqlWhere(); } return Product::countPublishedBy($arrColumns, $queryBuilder->getSqlValues()); }
/** * Checks whether a product is new according to the current store config * * @return bool */ public function isNew() { return $this->dateAdded >= Isotope::getConfig()->getNewProductLimit(); }
public static function updateStock(Order $objOrder, $objNewStatus) { // atm only for backend if (TL_MODE != 'BE') { return false; } // the order's config is used! $objConfig = Isotope::getConfig(); $arrStockIncreaseOrderStates = deserialize($objConfig->stockIncreaseOrderStates, true); // e.g. new -> cancelled => increase the stock based on the order item's setQuantity-values (no validation required, of course) if (!in_array($objOrder->order_status, $arrStockIncreaseOrderStates) && in_array($objNewStatus->id, $arrStockIncreaseOrderStates)) { foreach ($objOrder->getItems() as $objItem) { if (($objProduct = $objItem->getProduct()) !== null) { $intTotalQuantity = static::getTotalStockQuantity($objItem->quantity, $objProduct, null, $objItem->setQuantity); if ($intTotalQuantity) { $objProduct->stock += $intTotalQuantity; $objProduct->save(); } } } } elseif (in_array($objOrder->order_status, $arrStockIncreaseOrderStates) && !in_array($objNewStatus->id, $arrStockIncreaseOrderStates)) { foreach ($objOrder->getItems() as $objItem) { if (($objProduct = $objItem->getProduct()) !== null) { $blnSkipValidation = static::getOverridableStockProperty('skipStockValidation', $objProduct); // watch out: also in backend the current set quantity is used for validation! if (!$blnSkipValidation && !static::validateQuantity($objProduct, $objItem->quantity)) { // if the validation breaks for only one product collection item -> cancel the order status transition return true; } } } foreach ($objOrder->getItems() as $objItem) { if (($objProduct = $objItem->getProduct()) !== null) { $intTotalQuantity = static::getTotalStockQuantity($objItem->quantity, $objProduct); if ($intTotalQuantity) { $objProduct->stock -= $intTotalQuantity; if ($objProduct->stock <= 0 && !static::getOverridableStockProperty('skipExemptionFromShippingWhenStockEmpty', $objProduct)) { $objProduct->shipping_exempt = true; } $objProduct->save(); } } } } // don't cancel return false; }
/** * Compile the list of hCard tokens for this address * * @param array $arrFields * * @return array */ public function getTokens($arrFields = null) { global $objPage; if (!is_array($arrFields)) { $arrFields = Isotope::getConfig()->getBillingFieldsConfig(); } $arrTokens = array('outputFormat' => $objPage->outputFormat); foreach ($arrFields as $arrField) { $strField = $arrField['value']; // Set an empty value for disabled fields, otherwise the token would not be replaced if (!$arrField['enabled']) { $arrTokens[$strField] = ''; continue; } if ($strField == 'subdivision' && $this->subdivision != '') { $arrSubdivisions = \Isotope\Backend::getSubdivisions(); list($country, $subdivion) = explode('-', $this->subdivision); $arrTokens['subdivision'] = $arrSubdivisions[strtolower($country)][$this->subdivision]; $arrTokens['subdivision_abbr'] = $subdivion; continue; } $arrTokens[$strField] = Format::dcaValue(static::$strTable, $strField, $this->{$strField}); } /** * Generate hCard fields * See http://microformats.org/wiki/hcard */ // Set "fn" (full name) to company if no first- and lastname is given if ($arrTokens['company'] != '') { $fn = $arrTokens['company']; $fnCompany = ' fn'; } else { $fn = trim($arrTokens['firstname'] . ' ' . $arrTokens['lastname']); $fnCompany = ''; } $street = implode($objPage->outputFormat == 'html' ? '<br>' : '<br />', array_filter(array($this->street_1, $this->street_2, $this->street_3))); $arrTokens += array('hcard_fn' => $fn ? '<span class="fn">' . $fn . '</span>' : '', 'hcard_n' => $arrTokens['firstname'] || $arrTokens['lastname'] ? '1' : '', 'hcard_honorific_prefix' => $arrTokens['salutation'] ? '<span class="honorific-prefix">' . $arrTokens['salutation'] . '</span>' : '', 'hcard_given_name' => $arrTokens['firstname'] ? '<span class="given-name">' . $arrTokens['firstname'] . '</span>' : '', 'hcard_family_name' => $arrTokens['lastname'] ? '<span class="family-name">' . $arrTokens['lastname'] . '</span>' : '', 'hcard_org' => $arrTokens['company'] ? '<div class="org' . $fnCompany . '">' . $arrTokens['company'] . '</div>' : '', 'hcard_email' => $arrTokens['email'] ? '<a href="mailto:' . $arrTokens['email'] . '">' . $arrTokens['email'] . '</a>' : '', 'hcard_tel' => $arrTokens['phone'] ? '<div class="tel">' . $arrTokens['phone'] . '</div>' : '', 'hcard_adr' => $street | $arrTokens['city'] || $arrTokens['postal'] || $arrTokens['subdivision'] || $arrTokens['country'] ? '1' : '', 'hcard_street_address' => $street ? '<div class="street-address">' . $street . '</div>' : '', 'hcard_locality' => $arrTokens['city'] ? '<span class="locality">' . $arrTokens['city'] . '</span>' : '', 'hcard_region' => $arrTokens['subdivision'] ? '<span class="region">' . $arrTokens['subdivision'] . '</span>' : '', 'hcard_region_abbr' => $arrTokens['subdivision_abbr'] ? '<abbr class="region" title="' . $arrTokens['subdivision'] . '">' . $arrTokens['subdivision_abbr'] . '</abbr>' : '', 'hcard_postal_code' => $arrTokens['postal'] ? '<span class="postal-code">' . $arrTokens['postal'] . '</span>' : '', 'hcard_country_name' => $arrTokens['country'] ? '<div class="country-name">' . $arrTokens['country'] . '</div>' : ''); return $arrTokens; }
/** * Return true or false depending on if shipping method is available * @return bool * @todo must check availability for a specific product collection (and not hardcoded to the current cart) */ public function isAvailable() { if (!$this->enabled && BE_USER_LOGGED_IN !== true) { return false; } if ($this->guests && FE_USER_LOGGED_IN === true || $this->protected && FE_USER_LOGGED_IN !== true) { return false; } if ($this->protected) { $arrGroups = deserialize($this->groups); if (!is_array($arrGroups) || empty($arrGroups) || !count(array_intersect($arrGroups, \FrontendUser::getInstance()->groups))) { return false; } } if ($this->minimum_total > 0 && $this->minimum_total > Isotope::getCart()->getSubtotal() || $this->maximum_total > 0 && $this->maximum_total < Isotope::getCart()->getSubtotal()) { return false; } $objScale = Isotope::getCart()->addToScale(); if (($minWeight = Weight::createFromTimePeriod($this->minimum_weight)) !== null && $objScale->isLessThan($minWeight)) { return false; } if (($maxWeight = Weight::createFromTimePeriod($this->maximum_weight)) !== null && $objScale->isMoreThan($maxWeight)) { return false; } if ($this->minimum_quantity > 0 || $this->maximum_quantity > 0) { $quantity = 0; if ('cart_items' !== $this->quantity_mode && 'cart_products' !== $this->quantity_mode) { throw new \InvalidArgumentException(sprintf('Unknown quantity mode "%s"', $this->quantity_mode)); } foreach (Isotope::getCart()->getItems() as $item) { if (!$item->hasProduct() || !$item->getProduct()->isExemptFromShipping()) { $quantity += 'cart_items' === $this->quantity_mode ? $item->quantity : 1; } } if ($this->minimum_quantity > 0 && $this->minimum_quantity > $quantity || $this->maximum_quantity > 0 && $this->maximum_quantity < $quantity) { return false; } } $arrConfigs = deserialize($this->config_ids); if (is_array($arrConfigs) && !empty($arrConfigs) && !in_array(Isotope::getConfig()->id, $arrConfigs)) { return false; } $objAddress = Isotope::getCart()->getShippingAddress(); $arrCountries = deserialize($this->countries); if (is_array($arrCountries) && !empty($arrCountries)) { if (!in_array($objAddress->country, $arrCountries)) { return false; } $arrSubdivisions = deserialize($this->subdivisions); if (is_array($arrSubdivisions) && !empty($arrSubdivisions) && !in_array($objAddress->subdivision, $arrSubdivisions)) { return false; } } // Check if address has a valid postal code if ($this->postalCodes != '') { $arrCodes = \Isotope\Frontend::parsePostalCodes($this->postalCodes); if (!in_array($objAddress->postal, $arrCodes)) { return false; } } if ($this->product_types_condition != 'calculation') { $arrConfigTypes = deserialize($this->product_types); if (is_array($arrConfigTypes) && !empty($arrConfigTypes)) { $arrItems = Isotope::getCart()->getItems(); $arrItemTypes = array(); foreach ($arrItems as $objItem) { if ($objItem->hasProduct()) { $arrItemTypes[] = $objItem->getProduct()->type; } elseif ($this->product_types_condition == 'onlyAvailable') { // If one product in cart is not of given type, shipping method is not available return false; } } $arrItemTypes = array_unique($arrItemTypes); switch ($this->product_types_condition) { case 'onlyAvailable': if (count(array_diff($arrItemTypes, $arrConfigTypes)) > 0) { return false; } break; case 'oneAvailable': if (count(array_intersect($arrConfigTypes, $arrItemTypes)) == 0) { return false; } break; case 'allAvailable': if (count(array_intersect($arrConfigTypes, $arrItemTypes)) != count($arrConfigTypes)) { return false; } break; default: throw new \UnexpectedValueException('Unknown product type condition "' . $this->product_types_condition . '"'); } } } return true; }
/** * Edit an address record. Based on the PersonalData core module * @param integer * @return void */ protected function edit($intAddressId = 0) { $table = Address::getTable(); \System::loadLanguageFile(\MemberModel::getTable()); $this->Template = new \Isotope\Template($this->memberTpl); $this->Template->hasError = false; $this->Template->slabel = specialchars($GLOBALS['TL_LANG']['MSC']['saveData']); if ($intAddressId === 0) { $objAddress = Address::createForMember(\FrontendUser::getInstance()->id); } else { $objAddress = Address::findOneForMember($intAddressId, \FrontendUser::getInstance()->id); } if (null === $objAddress) { global $objPage; \Controller::redirect(\Controller::generateFrontendUrl($objPage->row())); } $objForm = new Form($table . '_' . $this->id, 'POST', function ($objForm) { return \Input::post('FORM_SUBMIT') === $objForm->getFormId(); }, (bool) $this->tableless); $objForm->bindModel($objAddress); // Add form fields and modify for the address book $arrFields = $this->arrFields; $objForm->addFieldsFromDca($table, function ($strName, &$arrDca) use($arrFields) { if (!in_array($strName, $arrFields) || !$arrDca['eval']['feEditable']) { return false; } // Map checkboxWizard to regular checkbox widget if ($arrDca['inputType'] == 'checkboxWizard') { $arrDca['inputType'] = 'checkbox'; } // Special field "country" if ($strName == 'country') { $arrCountries = array_merge(Isotope::getConfig()->getBillingCountries(), Isotope::getConfig()->getShippingCountries()); $arrDca['reference'] = $arrDca['options']; $arrDca['options'] = array_values(array_intersect(array_keys($arrDca['options']), $arrCountries)); $arrDca['default'] = Isotope::getConfig()->billing_country; } return true; }); if ($objForm->isSubmitted()) { if ($objForm->validate()) { $objAddress->save(); // Call onsubmit_callback if (is_array($GLOBALS['TL_DCA'][$table]['config']['onsubmit_callback'])) { foreach ($GLOBALS['TL_DCA'][$table]['config']['onsubmit_callback'] as $callback) { $objCallback = \System::importStatic($callback[0]); $objCallback->{$callback}[1]($objAddress); } } global $objPage; \Controller::redirect(\Controller::generateFrontendUrl($objPage->row())); } else { $this->Template->hasError = true; } } $objForm->addToTemplate($this->Template); // Add groups $arrGroups = array(); foreach ($objForm->getFormFields() as $strName => $arrConfig) { if ($arrConfig['feGroup'] != '') { $arrGroups[$arrConfig['feGroup']][$strName] = $objForm->getWidget($strName)->parse(); } } foreach ($arrGroups as $k => $v) { $this->Template->{$k} = $v; } $this->Template->addressDetails = $GLOBALS['TL_LANG'][$table]['addressDetails']; $this->Template->contactDetails = $GLOBALS['TL_LANG'][$table]['contactDetails']; $this->Template->personalData = $GLOBALS['TL_LANG'][$table]['personalData']; $this->Template->loginDetails = $GLOBALS['TL_LANG'][$table]['loginDetails']; }
/** * Get allowed countries for this address type * @return array */ protected function getAddressCountries() { return Isotope::getConfig()->getShippingCountries(); }
/** * Function to build an array for Origin, Destination, and Shipment based on ProductCollection * * @access protected * @param IsotopeProductCollection * @return array */ protected function buildShipment(IsotopeProductCollection $objCollection) { if (TL_MODE !== 'FE') { return array(); } $arrItems = $objCollection->getItems(); $arrProductIds = array(); $arrProducts = array(); foreach ($arrItems as $objItem) { $arrProductIds[] = $objItem->id; $arrProducts[] = $objItem->getProduct(); } //todo account for multiple packages per order $arrShipment = array('address' => $objCollection->getShippingAddress()->row(), 'products' => $arrProducts, 'productids' => $arrProductIds); //Build a Shipments array from passed data or the current cart $this->Shipment = $arrShipment; $arrSubDivisionShipping = explode('-', $arrShipment['address']['subdivision']); $arrDestination = array('name' => $arrShipment['address']['firstname'] . ' ' . $arrShipment['address']['lastname'], 'company' => $arrShipment['address']['company'], 'street' => strtoupper($arrShipment['address']['street_1']), 'street2' => strtoupper($arrShipment['address']['street_2']), 'street3' => strtoupper($arrShipment['address']['street_3']), 'city' => strtoupper($arrShipment['address']['city']), 'state' => $arrSubDivisionShipping[1], 'zip' => $arrShipment['address']['postal'], 'country' => strtoupper($arrShipment['address']['country'])); $arrSubDivisionStore = explode('-', Isotope::getConfig()->subdivision); $arrOrigin = array('name' => Isotope::getConfig()->company, 'phone' => Isotope::getConfig()->phone, 'company' => Isotope::getConfig()->company, 'street' => strtoupper(Isotope::getConfig()->street_1), 'street2' => strtoupper(Isotope::getConfig()->street_2), 'street3' => strtoupper(Isotope::getConfig()->street_3), 'city' => strtoupper(Isotope::getConfig()->city), 'state' => $arrSubDivisionStore[1], 'zip' => Isotope::getConfig()->postal, 'country' => strtoupper(Isotope::getConfig()->country), 'number' => Isotope::getConfig()->FedExAccountNumber); $arrShipment['service'] = strlen($this->fedex_enabledService) ? $this->fedex_enabledService : 'FEDEX_GROUND'; //Ground for now $arrShipment['packaging_type'] = strlen($this->fedex_PackingService) ? $this->fedex_PackingService : 'YOUR_PACKAGING'; $arrShipment['pickup_type'] = array('code' => '03', 'description' => ''); //todo - option for one package per product foreach ($objCollection->getItems() as $objItem) { $product = $objItem->getProduct(); $arrDimensions = deserialize($product->package_dimensions, true); $fltWeight = $this->getShippingWeight($objItem, 'lb'); $fltInsurance = round($this->insuranceIsPercentage() ? $this->getInsurancePercentage() / 100 * $product->getPrice()->getAmount(1) : floatval($this->arrData['fedex_insurance']), 2); for ($i = 0; $i < $objItem->quantity; $i++) { $arrShipment['packages'][] = array('packaging' => array('code' => '02', 'description' => 'Customer Supplied'), 'insuredValue' => $fltInsurance, 'units' => 'LBS', 'weight' => ceil($fltWeight ?: 1), 'dimensions' => array('length' => floatval($arrDimensions[0]) ?: 1, 'width' => floatval($arrDimensions[1]) ?: 1, 'height' => floatval($arrDimensions[2]) ?: 1)); } } return array($arrOrigin, $arrDestination, $arrShipment); }