/**
  * Create a unique code. If a code generated isn't unique, the method will call itself to attempt to create a new
  * one. If the method cannot create a unique code in the number of times set by the LIMIT constant, an exception
  * will be thrown.
  *
  * @throws Exception\DiscountBuildException
  *
  * @return string
  */
 private function _getCode()
 {
     $code = $this->_generateCode();
     if (false === $this->_loader->getByCode($code)) {
         return $code;
     }
     $this->_codes[] = $code;
     if (count($this->_codes) > self::LIMIT) {
         throw new Exception\DiscountBuildException('Could not create a unique discount code in ' . self::LIMIT . ' attempts');
     }
     return $this->_getCode();
 }
 /**
  * Validates a discount by it's discountCode and an order
  * and returns an order-discount-object.
  * Checks validity of the code, whether it is active and
  * (if the discount applies to specific products) whether
  * the at least one of the items in the order matches one
  * of the discount's products.
  *
  * @param string $discountCode The code of the discount validated
  *
  * @throws OrderValidityException if the validation failed
  *
  * @return Order\Entity\Discount\Discount the order-discount-object for the given discountCode
  */
 public function validate($discountCode, $adding = true)
 {
     $adding = (bool) $adding;
     if (null === $this->_order) {
         throw new \Exception('Order must be set before discount code can be validated');
     }
     $this->_validateNoRestrictedBundles();
     $this->_validateMaxNumberDiscounts($adding);
     if ($adding) {
         $this->_validateAlreadyUsed($discountCode);
     }
     if (0 === $this->_order->items->count()) {
         throw new OrderValidityException('Your basket is empty');
     }
     $discount = $this->_discountLoader->getByCode($discountCode);
     if (!$discount) {
         throw new OrderValidityException('The entered code was not recognised.');
     }
     if (!$discount->isActive()) {
         $message = $discount->start < new \DateTime() ? 'The discount has expired.' : 'The discount is not active yet.';
         throw new OrderValidityException($message);
     }
     // check whether discount-threshold is reached
     if (0 !== count($discount->thresholds)) {
         foreach ($discount->thresholds as $currencyID => $threshold) {
             if ($this->_order->currencyID === $currencyID) {
                 if ($this->_order->productGross < $threshold) {
                     throw new OrderValidityException('Your order value is less than the discount threshold.');
                 }
             }
         }
     }
     // check whether order has at least one of the products the discount applies to
     if (!$discount->appliesToOrder) {
         $appliesToItem = false;
         foreach ($discount->products as $product) {
             foreach ($this->_order->items->all() as $item) {
                 if ($item->productID === $product->id) {
                     $appliesToItem = true;
                     break;
                 }
             }
             if ($appliesToItem) {
                 break;
             }
         }
         if (!$appliesToItem) {
             throw new OrderValidityException('Your order does not include any of the products the discount applies to.');
         }
     }
     if (empty($discount->discountAmounts[$this->_order->currencyID]) && !$discount->percentage && !$discount->freeShipping) {
         throw new OrderValidityException('Discount not available in this currency');
     }
     $this->_validateEmail($discount);
     $this->_orderDiscountFactory->setOrder($this->_order)->setDiscount($discount);
     return $this->_orderDiscountFactory->createOrderDiscount();
 }