/**
  * Main function that determines what the result does
  * @param \Heystack\Deals\Interfaces\DealHandlerInterface $dealHandler
  * @return \SebastianBergmann\Money\Money
  */
 public function process(DealHandlerInterface $dealHandler)
 {
     $discount = $this->getCurrencyService()->getZeroMoney();
     $dealIdentifier = $dealHandler->getIdentifier();
     // Reset the free count for this deal of all the purchasables. We need to do this because
     // a new 'cheaper' product may have been added to the purchasable holder in the meantime
     foreach ($this->purchasableHolder->getPurchasables() as $purchasable) {
         if ($purchasable instanceof DealPurchasableInterface) {
             $purchasable->setFreeQuantity($dealIdentifier, 0);
             $purchasable->setDealDiscount($dealIdentifier, $discount);
         }
     }
     $remainingFreeDiscounts = $dealHandler->getConditionsMetCount();
     $purchasables = $this->getPurchsablesSortedByUnitPrice();
     $purchasable = current($purchasables);
     while ($purchasable && $remainingFreeDiscounts > 0) {
         // Skip if it isn't a deal purchasable
         if (!$purchasable instanceof DealPurchasableInterface) {
             $purchasable = next($purchasable);
             continue;
         }
         // Get the smaller number, either the quantity of the current purchasable
         // or the remaining free discounts
         $freeQuantity = min($purchasable->getQuantity(), $remainingFreeDiscounts);
         // Get the current discount
         $currentPurchasableDiscount = $purchasable->getDealDiscountWithExclusions([$dealIdentifier->getFull()]);
         $purchasableTotal = $purchasable->getTotal();
         $purchasableDiscount = $purchasable->getUnitPrice()->multiply($freeQuantity);
         // When the deduction exceeds the remaining money just remove the remaining money
         if ($currentPurchasableDiscount->add($purchasableDiscount)->greaterThan($purchasableTotal)) {
             $purchasableDiscount = $purchasableTotal->subtract($currentPurchasableDiscount);
         }
         $discount = $discount->add($purchasableDiscount);
         $purchasable->setFreeQuantity($dealIdentifier, $freeQuantity);
         $purchasable->setDealDiscount($dealHandler->getIdentifier(), $purchasableDiscount);
         $remainingFreeDiscounts -= $freeQuantity;
         // Advance to the next purchasable
         $purchasable = next($purchasables);
     }
     $this->purchasableHolder->updateTotal();
     $this->eventService->dispatch(Events::RESULT_PROCESSED, new ResultEvent($this));
     return $this->totalDiscount = $discount;
 }
 /**
  * Applies the free gift to the purchasable holder.
  *
  * The event dispatcher is disabled here to not cause recursion as the free gift is added to the cart. In normal
  * circumstances adding a purchasable to the purschasable holder causes deal conditions to be re-evaluated, and
  * results of those conditions applied. Obviously in this situation, adding a free gift to the cart may cause those
  * events to fire causing other purchasables to be added as a result - leading to a bad situation
  *
  * There are two cases where the free gift must be added the purchasable holder
  *
  *  1) when the purchasable has already been added to the cart, but none are yet free.
  *  2) when the purchasable has already been added to the cart but the purchasables free quantity is less than the
  *     current amount of times this condition has been met.
  *
  * @param \Heystack\Deals\Events\ConditionEvent $event
  * @param string $eventName
  * @param \Heystack\Core\EventDispatcher $dispatcher
  * @return void
  */
 public function onConditionsMet(ConditionEvent $event, $eventName, EventDispatcher $dispatcher)
 {
     // Should we get the event dispatcher off the event?
     $deal = $this->getDealHandler();
     $dealIdentifier = $deal->getIdentifier();
     $conditionsMetCount = $deal->getConditionsMetCount();
     $purchasableHolder = $this->getPurchasableHolder();
     // Only do stuff if it is relevant to this deal
     if ($dealIdentifier->isMatch($event->getDealHandler()->getIdentifier())) {
         $dispatcher->setEnabled(false);
         $purchasable = $this->getPurchasable();
         if ($purchasable instanceof DealPurchasableInterface) {
             $purchasableAlreadyInCart = $this->purchasableHolder->getPurchasable($purchasable->getIdentifier());
             if (!$purchasableAlreadyInCart instanceof DealPurchasableInterface) {
                 $this->purchasableHolder->setPurchasable($purchasable, 0);
             }
             $purchasable->setFreeQuantity($dealIdentifier, $conditionsMetCount);
         }
         $dispatcher->setEnabled(true);
         $purchasableHolder->updateTotal();
     }
 }
 /**
  * @param \SS_HTTPRequest $request
  * @param \SS_HTTPResponse $response
  * @param \DataModel $model
  * @return void
  */
 public function postRequest(SS_HTTPRequest $request, SS_HTTPResponse $response, DataModel $model)
 {
     if ($this->eventDispatcher instanceof EventDispatcher) {
         $this->eventDispatcher->dispatch(Events::POST_REQUEST);
     }
 }