public function screen() { if (!current_user_can('shopp_promotions')) { wp_die(__('You do not have sufficient permissions to access this page.')); } $table = ShoppDatabaseObject::tablename(ShoppPromo::$table); $defaults = array('page' => false, 'status' => false, 'type' => false, 'paged' => 1, 'per_page' => 20, 's' => ''); $args = array_merge($defaults, $_GET); extract($args, EXTR_SKIP); $url = add_query_arg(array_merge($_GET, array('page' => $this->page)), admin_url('admin.php')); $f = array('action', 'selected', 's'); $url = remove_query_arg($f, $url); $pagenum = absint($paged); $start = $per_page * ($pagenum - 1); $where = array(); if (!empty($s)) { $where[] = "name LIKE '%{$s}%'"; } if ($status) { $datesql = ShoppPromo::activedates(); switch (strtolower($status)) { case 'active': $where[] = "status='enabled' AND {$datesql}"; break; case 'inactive': $where[] = "status='enabled' AND NOT {$datesql}"; break; case 'enabled': $where[] = "status='enabled'"; break; case 'disabled': $where[] = "status='disabled'"; break; } } if ($type) { switch (strtolower($type)) { case 'catalog': $where[] = "target='Catalog'"; break; case 'cart': $where[] = "target='Cart'"; break; case 'cartitem': $where[] = "target='Cart Item'"; break; } } $select = sDB::select(array('table' => $table, 'columns' => 'SQL_CALC_FOUND_ROWS *', 'where' => $where, 'orderby' => 'created DESC', 'limit' => "{$start},{$per_page}")); $Promotions = sDB::query($select, 'array'); $count = sDB::found(); $num_pages = ceil($count / $per_page); $ListTable = ShoppUI::table_set_pagination($this->id, $count, $num_pages, $per_page); $states = array('active' => __('Active', 'Shopp'), 'inactive' => __('Not Active', 'Shopp'), 'enabled' => __('Enabled', 'Shopp'), 'disabled' => __('Disabled', 'Shopp')); $types = array('catalog' => __('Catalog Discounts', 'Shopp'), 'cart' => __('Cart Discounts', 'Shopp'), 'cartitem' => __('Cart Item Discounts', 'Shopp')); $num_pages = ceil($count / $per_page); $page_links = paginate_links(array('base' => add_query_arg('pagenum', '%#%'), 'format' => '', 'total' => $num_pages, 'current' => $pagenum)); include $this->ui('discounts.php'); }
protected function save() { if (empty($_POST['save'])) { return; } check_admin_referer('shopp-save-discount'); if ('new' !== $_POST['id']) { $Promotion = new ShoppPromo($_POST['id']); $wascatalog = 'Catalog' == $Promotion->target; } else { $Promotion = new ShoppPromo(); } if (!empty($_POST['starts']['month']) && !empty($_POST['starts']['date']) && !empty($_POST['starts']['year'])) { $_POST['starts'] = mktime(0, 0, 0, $_POST['starts']['month'], $_POST['starts']['date'], $_POST['starts']['year']); } else { $_POST['starts'] = 1; } if (!empty($_POST['ends']['month']) && !empty($_POST['ends']['date']) && !empty($_POST['ends']['year'])) { $_POST['ends'] = mktime(23, 59, 59, $_POST['ends']['month'], $_POST['ends']['date'], $_POST['ends']['year']); } else { $_POST['ends'] = 1; } if (isset($_POST['rules'])) { $_POST['rules'] = stripslashes_deep($_POST['rules']); foreach ($_POST['rules'] as &$rule) { if ('promo code' == strtolower($rule['property'])) { $rule['value'] = trim($rule['value']); } if (false !== stripos($rule['property'], 'country') && 'USA' == $rule['value']) { $rule['value'] = 'US'; } // country-based rules must use 2-character ISO code, see #3129 } } $Promotion->updates($_POST); $Promotion->save(); do_action_ref_array('shopp_promo_saved', array(&$Promotion)); // Apply catalog promotion discounts to catalog product price lines if ('Catalog' == $Promotion->target) { $Promotion->catalog(); } elseif ($wascatalog) { // Unapply catalog discounts for discounts that no longer target catalog products $priceids = ShoppPromo::discounted_prices(array($Promotion->id)); $Promotion->uncatalog($priceids); } // Set confirmation notice $this->notice(Shopp::__('Promotion has been updated!')); // Stay in the editor $url = add_query_arg('id', $Promotion->id, $this->url); wp_redirect($url); exit; }
/** * Set or load the discounts applied to this order * * @author Jonathan Davis * @since 1.3 * * @param ShoppDiscounts $ShoppDiscounts The ShoppDiscounts object from the order to add to this purchase * @return array List of discounts applied **/ public function discounts(ShoppDiscounts $ShoppDiscounts = null) { if (empty($this->id)) { return false; } if (isset($ShoppDiscounts)) { // Save the given discounts $discounts = array(); foreach ($ShoppDiscounts as $Discount) { $discounts[$Discount->id()] = new ShoppPurchaseDiscount($Discount); } shopp_set_meta($this->id, 'purchase', 'discounts', $discounts); $this->discounts = $discounts; ShoppPromo::used(array_keys($discounts)); } if (empty($this->discounts)) { $this->discounts = shopp_meta($this->id, 'purchase', 'discounts'); } return $this->discounts; }
/** * Match a rule to the item * * @author Jonathan Davis * @since 1.1 * * @param array $rule A structured rule array * @return boolean **/ public function match($rule) { extract($rule); switch ($property) { case 'Any item name': $subject = $this->name; break; case 'Any item quantity': $subject = (int) $this->quantity; break; case 'Any item amount': $subject = $this->total; break; case 'Name': $subject = $this->name; break; case 'Category': $subject = $this->categories; break; case 'Tag name': $subject = $this->tags; break; case 'Variation': $subject = $this->option->label; break; case 'Input name': foreach ($this->data as $inputName => $inputValue) { if (ShoppPromo::match_rule($inputName, $logic, $value, $property)) { return true; } } return false; case 'Input value': foreach ($this->data as $inputName => $inputValue) { if (ShoppPromo::match_rule($inputValue, $logic, $value, $property)) { return true; } } return false; case 'Quantity': $subject = $this->quantity; break; case 'Unit price': $subject = $this->unitprice; break; case 'Total price': $subject = $this->total; break; case 'Discount amount': $subject = $this->discount; break; } return ShoppPromo::match_rule($subject, $logic, $value, $property); }
/** * Aggregates product pricing information * * @author Jonathan Davis * @since 1.1 * * @param array $options shopp() tag option list * @return void **/ public function pricing(&$records, &$price, $restat = false) { if (isset($this->products) && !empty($this->products)) { if (!isset($this->products[$price->product])) { return false; } if (!isset($this->_last_product)) { $this->_last_product = false; } if ($this->_last_product != false && $this->_last_product != $price->product && isset($this->products[$this->_last_product])) { $this->products[$this->_last_product]->sumup(); } if ($this->_last_product != $price->product) { $this->products[$price->product]->resum(); } $target =& $this->products[$price->product]; $this->_last_product = $price->product; } else { $target =& $this; } // Skip calulating variant pricing when variants are not enabled for the product if (!(isset($target->variants) && Shopp::str_true($target->variants)) && 'variation' == $price->context) { return; } $target->prices[] = $price; // Force to floats $price->price = (double) $price->price; $price->saleprice = (double) $price->saleprice; $price->shipfee = (double) $price->shipfee; $price->promoprice = (double) Shopp::str_true($price->sale) ? $price->saleprice : $price->price; // Build secondary lookup table using the price id as the key $target->priceid[$price->id] = $price; // Set promoprice before data aggregation if (Shopp::str_true($price->sale)) { $price->promoprice = $price->saleprice; } // Do not count disabled price lines or addon price lines in aggregate summary stats if ('N/A' == $price->type || 'addon' == $price->context) { return; } // Simple product or variant product is on sale if (Shopp::str_true($price->sale)) { $target->sale = $price->sale; } // Build third lookup table using the combined optionkey $target->pricekey[$price->optionkey] = $price; if (Shopp::str_true($price->inventory)) { $target->stock += $price->stock; $target->inventory = $price->inventory; $target->lowstock($price->stock, $price->stocked); } $freeshipping = false; if (!Shopp::str_true($price->shipping) && 'Shipped' == $price->type) { $freeshipping = true; } // Calculate catalog discounts if not already calculated if (!empty($price->discounts)) { $discount = ShoppPromo::pricing($price->promoprice, $price->discounts); if ($discount->freeship) { $freeshipping = true; } $price->promoprice = $discount->pricetag; } $price->_sale = $price->sale; // Keep a copy of the price record "sale" setting {@see issue #2797} if ($price->promoprice < $price->price) { $target->sale = $price->sale = 'on'; } // Grab price and saleprice ranges (minimum - maximum) if (!$price->price) { $price->price = 0; } // Variation range index/properties $varranges = array('price' => 'price', 'saleprice' => 'promoprice'); if (Shopp::str_true($price->inventory)) { $varranges['stock'] = 'stock'; } foreach ($varranges as $name => $prop) { if (!isset($price->{$prop})) { continue; } if (!isset($target->min[$name]) || $target->min[$name] == 0) { $target->min[$name] = $price->{$prop}; } else { $target->min[$name] = min($target->min[$name], $price->{$prop}); } if ($target->min[$name] == $price->{$prop}) { $target->min[$name . '_tax'] = $price->tax == "on"; } if (!isset($target->max[$name])) { $target->max[$name] = $price->{$prop}; } else { $target->max[$name] = max($target->max[$name], $price->{$prop}); } if ($target->max[$name] == $price->{$prop}) { $target->max[$name . '_tax'] = $price->tax == "on"; } } // Determine savings ranges if (Shopp::str_true($target->sale)) { if (!isset($target->min['saved']) || $target->min['saved'] === false) { $target->min['saved'] = $price->price; $target->min['savings'] = 100; $target->max['saved'] = $target->max['savings'] = 0; } $target->min['saved'] = min($target->min['saved'], $price->price - $price->promoprice); $target->max['saved'] = max($target->max['saved'], $price->price - $price->promoprice); // Find lowest savings percentage $delta = $price->price - $price->promoprice; if ($price->price == 0) { // no savings possible $target->min['savings'] = 0; } else { if ($delta <= 0) { // total savings $target->max['savings'] = 100; } else { $savings = $delta / $price->price * 100; $target->min['savings'] = min($target->min['savings'], $savings); $target->max['savings'] = max($target->max['savings'], $savings); } } } if (shopp_setting_enabled('inventory') && Shopp::str_true($target->inventory)) { $target->outofstock = $target->stock <= 0; } if ($freeshipping) { $target->freeship = 'on'; } }
/** * Load active promotions * * @author Jonathan Davis * @since 1.3 * * @return array List of loaded ShoppOrderPromo objects **/ public function load() { if ($this->loaded) { return; } // Don't load twice in one request $table = ShoppDatabaseObject::tablename(ShoppPromo::$table); $where = array("status='enabled'", ShoppPromo::activedates(), "target IN ('" . join("','", self::$targets) . "')"); $orderby = 'target DESC'; $queryargs = compact('table', 'where', 'orderby'); $query = sDB::select($queryargs); $loaded = sDB::query($query, 'array', array('ShoppPromotions', 'loader')); if (!$loaded || 0 == count($loaded)) { return; } $this->populate($loaded); $this->loaded = true; }
/** * Calculates promotional discounts applied to the price record * * @author Jonathan Davis * @since 1.1 * * @return boolean True if a discount applies **/ public function discounts() { if (empty($this->discounts)) { return false; } $pricetag = Shopp::str_true($this->sale) ? $this->saleprice : $this->price; $discount = ShoppPromo::pricing($pricetag, $this->discounts); $this->promoprice = $discount->pricetag; if ($discount->freeship) { $this->freeship = true; } return true; }
/** * Disables an entire set of promotions * * @author Jonathan Davis * @since 1.2 * * @param array $ids List of promotion IDs to disable * @return boolean Success/fail **/ static function disableset($ids) { if (empty($ids) || !is_array($ids)) { return false; } $table = ShoppDatabaseObject::tablename(self::$table); sDB::query("UPDATE {$table} SET status='disabled' WHERE id IN (" . join(',', $ids) . ")"); $catalogpromos = sDB::query("SELECT id FROM {$table} WHERE target='Catalog'", 'array', 'col', 'id'); foreach ($catalogpromos as $promoid) { $Promo = new ShoppPromo($promoid); $Promo->catalog(); } return true; }