/** * Matches a Promo Code rule to a code submitted from the shopping cart * * @since 1.1 * * @param array $rule The promo code rule * @return boolean **/ function promocode ($rule) { extract($rule); $promocode = strtolower($value); // Match previously applied codes if (isset($this->Cart->promocodes[$promocode]) && is_array($this->Cart->promocodes[$promocode])) return true; // Match new codes // No code provided, nothing will match if (empty($this->Cart->promocode)) return false; $subject = strtolower($this->Cart->promocode); return Promotion::match_rule($subject,$logic,$promocode,$property); }
/** * Match a rule to the item * * @since 1.1 * * @param array $rule A structured rule array * @return boolean **/ 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": $subject = $Item->option->label; break; // case "Input value": $subject = $Item->option->label; break; 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 Promotion::match_rule($subject,$logic,$value,$property); }
/** * promotions() * Matches, calculates and applies promotion discounts */ function promotions() { global $Shopp; $db = DB::get(); $limit = $Shopp->Settings->get('promo_limit'); // Load promotions if they've not yet been loaded if (empty($this->data->Promotions)) { $promo_table = DatabaseObject::tablename(Promotion::$table); // Add date-based lookup too $this->data->Promotions = $db->query("SELECT * FROM {$promo_table} WHERE scope='Order' AND ((status='enabled' AND UNIX_TIMESTAMP(starts) > 0 AND UNIX_TIMESTAMP(starts) < UNIX_TIMESTAMP() AND UNIX_TIMESTAMP(ends) > UNIX_TIMESTAMP()) OR status='enabled')", AS_ARRAY); } $PromoCodeFound = false; $PromoCodeExists = false; $PromoLimit = false; $this->data->PromosApplied = array(); foreach ($this->data->Promotions as &$promo) { if (!is_array($promo->rules)) { $promo->rules = unserialize($promo->rules); } // Add quantity rule automatically for buy x get y promos if ($promo->type == "Buy X Get Y Free") { $promo->search = "all"; if ($promo->rules[count($promo->rules) - 1]['property'] != "Item quantity") { $qtyrule = array('property' => 'Item quantity', 'logic' => "Is greater than", 'value' => $promo->buyqty); $promo->rules[] = $qtyrule; } } $items = array(); $match = false; $rulematches = 0; foreach ($promo->rules as $rule) { $rulematch = false; switch ($rule['property']) { case "Item name": foreach ($this->contents as $id => &$Item) { if (Promotion::match_rule($Item->name, $rule['logic'], $rule['value'], $rule['property'])) { $items[$id] =& $Item; $rulematch = true; } } break; case "Item quantity": foreach ($this->contents as $id => &$Item) { if (Promotion::match_rule(number_format($Item->quantity, 0), $rule['logic'], $rule['value'], $rule['property'])) { $items[$id] =& $Item; $rulematch = true; } } break; case "Item amount": foreach ($this->contents as $id => &$Item) { if (Promotion::match_rule(number_format($Item->total, 2), $rule['logic'], $rule['value'], $rule['property'])) { $items[$id] =& $Item; $rulematch = true; } } break; case "Total quantity": if (Promotion::match_rule(number_format($this->data->Totals->quantity, 0), $rule['logic'], $rule['value'], $rule['property'])) { $rulematch = true; } break; case "Shipping amount": if (Promotion::match_rule(number_format($this->data->Totals->shipping, 2), $rule['logic'], $rule['value'], $rule['property'])) { $rulematch = true; } break; case "Subtotal amount": if (Promotion::match_rule(number_format($this->data->Totals->subtotal, 2), $rule['logic'], $rule['value'], $rule['property'])) { $rulematch = true; } break; case "Promo code": // Match previously applied codes if (is_array($this->data->PromoCodes) && in_array($rule['value'], $this->data->PromoCodes)) { $rulematch = true; break; } // Match a new code if (!empty($this->data->PromoCode)) { if (Promotion::match_rule($this->data->PromoCode, $rule['logic'], $rule['value'], $rule['property'])) { if (is_array($this->data->PromoCodes) && !in_array($this->data->PromoCode, $this->data->PromoCodes)) { $this->data->PromoCodes[] = $rule['value']; $PromoCodeFound = $rule['value']; } else { $PromoCodeExists = true; } $this->data->PromoCode = false; $rulematch = true; } } break; } if ($rulematch && $promo->search == "all") { $rulematches++; } if ($rulematch && $promo->search == "any") { $match = true; break; // One matched, no need to match any more } } // end foreach ($promo->rules) if ($promo->search == "all" && $rulematches == count($promo->rules)) { $match = true; } // Everything matches up, apply the promotion if ($match && !$PromoLimit) { // echo "Matched $promo->name".BR; if (!empty($items)) { $freeshipping = 0; // Apply promo calculation to specific cart items foreach ($items as $item) { switch ($promo->type) { case "Percentage Off": $this->data->Totals->discount += $item->total * ($promo->discount / 100); break; case "Amount Off": $this->data->Totals->discount += $promo->discount; break; case "Buy X Get Y Free": $this->data->Totals->discount += floor($item->quantity / ($promo->buyqty + $promo->getqty)) * $item->unitprice; break; case "Free Shipping": $freeshipping++; break; } } if ($freeshipping == count($this->contents) && $promo->scope == "Order") { $this->freeshipping = true; } else { $this->freeshipping = false; } } else { // Apply promo calculation to entire order switch ($promo->type) { case "Percentage Off": $this->data->Totals->discount += $this->data->Totals->subtotal * ($promo->discount / 100); break; case "Amount Off": $this->data->Totals->discount += $promo->discount; break; case "Free Shipping": $this->freeshipping = true; break; } } $this->data->PromosApplied[] = $promo; if ($limit > 0 && count($this->data->PromosApplied) + 1 > $limit) { $PromoLimit = true; break; } } if ($match && $promo->exclusive == "on") { break; } } // end foreach ($Promotions) // Promo code found, but ran into promotion limits if (!empty($this->data->PromoCode) && $PromoLimit) { $this->data->PromoCodeResult = __("No additional codes can be applied.", "Shopp"); $this->data->PromoCodes = array_diff($this->data->PromoCodes, array($PromoCodeFound)); $this->data->PromoCode = false; } // Promo code not found if (!empty($this->data->PromoCode) && !$PromoCodeFound && !$PromoCodeExists) { $this->data->PromoCodeResult = $this->data->PromoCode . ' ' . __("is not a valid code.", "Shopp"); $this->data->PromoCodes = array_diff($this->data->PromoCodes, array($this->data->PromoCode)); $this->data->PromoCode = false; } }