/**
  * Checks the stock level for all items in an order **only** if the order's
  * type is set as an applicable order type.
  *
  * If the quantity of a particular unit in the order is greater than the
  * amount in the defined stock location, the extra items are removed so the
  * quantity matches the stock level and a flash message is added to the
  * session.
  *
  * @param OrderEvent $event The event object
  */
 public function checkStock(OrderEvent $event)
 {
     $order = $event->getOrder();
     if (!in_array($order->type, $this->_orderTypes)) {
         return false;
     }
     $addFlash = false;
     $unitLoader = $this->get('product.unit.loader')->includeInvisible(true)->includeOutOfStock(true);
     foreach ($order->items->getRows() as $row) {
         $unit = $unitLoader->getByID($row->first()->unitID);
         $stock = $unit->getStockForLocation($row->first()->stockLocation);
         if ($row->getQuantity() > $stock) {
             $amountToRemove = $row->getQuantity() - $stock;
             $addFlash = true;
             foreach ($row as $item) {
                 if ($amountToRemove < 1) {
                     break;
                 }
                 $order->items->remove($item);
                 $amountToRemove--;
             }
         }
     }
     if ($addFlash) {
         $this->get('http.session')->getFlashBag()->add('warning', 'Some of the items in your basket are no longer available and have been removed.');
     }
 }
 /**
  * Decrement the additional discount statistics if the order was discounted.
  *
  * @param  Event\Event $event
  */
 public function recordDiscountRevenueDeleted(OrderEvent $event)
 {
     $order = $event->getOrder();
     if ($order->totalDiscount > 0) {
         $this->get('statistics')->get('discounted.sales.gross')->counter->decrement($order->totalGross);
         $this->get('statistics')->get('discount.gross')->counter->decrement($order->totalDiscount);
     }
 }
 /**
  * @param Order\Event\Event $event
  */
 public function sendOrderConfirmationMail(Order\Event\Event $event)
 {
     $order = $event->getOrder();
     $merchant = $this->get('cfg')->merchant;
     if ($order->type == 'web') {
         $payments = $this->get('order.payment.loader')->getByOrder($order);
         $factory = $this->get('mail.factory.order.confirmation')->set('order', $order)->set('payments', $payments);
         $this->get('mail.dispatcher')->send($factory->getMessage());
     }
 }
 /**
  * Resets the item's discount and sets the amount to 0 if the discount
  * is a percentage one.
  *
  * @param Event $event The event object
  */
 public function resetDiscountAmounts(Event\Event $event)
 {
     foreach ($event->getOrder()->items as $item) {
         $item->discount = 0;
     }
     foreach ($event->getOrder()->discounts as $discount) {
         if ($discount->percentage) {
             $discount->amount = 0;
         }
     }
 }
 public function updateDiscountEmail(Event\Event $event)
 {
     $order = $event->getOrder();
     foreach ($order->discounts as $orderDiscount) {
         if ($orderDiscount->code) {
             $discount = $this->get('discount.loader')->getByCode($orderDiscount->code);
             if (in_array($order->userEmail, $discount->emails)) {
                 $this->get('discount.edit')->markEmailAsUsed($discount, $order->userEmail);
             }
         }
     }
 }
 /**
  * Loop through bundles assigned to order and check that they are still valid. Add discount entities to the order
  * if the bundles are valid and the discount has not already been added to the order, and remove them if they
  * are invalid and have been set against the order.
  *
  * This method uses the metadata key for the bundle (i.e. 'bundle_[number]') as the ID for the discount entity.
  * The ID is not saved to the database so this only exists on the basket. This makes it easier to keep track of
  * which bundle is which.
  *
  * @param OrderEvent $event
  *
  * @return bool | string
  */
 public function validateBundle(OrderEvent $event)
 {
     $bundleIDs = $this->_getBundleIDs($event->getOrder());
     if (count($bundleIDs) <= 0) {
         return false;
     }
     $bundles = $this->get('discount.bundle_loader')->getByID($bundleIDs);
     $validator = $this->get('discount.bundle_validator');
     foreach ($bundleIDs as $metadataKey => $bundleID) {
         if (array_key_exists($metadataKey, $this->_bundleLog)) {
             // If the metadata key exists in the bundle log, the only reason this method is being called against is
             // because it  has just been added to the order, so we don't need to revalidate the bundle. Instead, we
             // remove it from the bundle log and break out of the loop.
             unset($this->_bundleLog[$metadataKey]);
             break;
         }
         $bundle = $bundles[$bundleID];
         $bundleExists = $this->get('basket.order')->discounts->exists($metadataKey);
         if ($bundleExists) {
             $this->get('basket.order')->discounts->remove($this->get('basket.order')->discounts->get($metadataKey));
         }
         // Validator will throw an exception if the bundle is not valid for the order. Remove the discount if it
         // has already been set and show a flash message.
         try {
             $validator->validate($bundle, $event->getOrder());
             $discount = $this->get('discount.bundle.order_discount_factory')->createOrderDiscount($event->getOrder(), $bundle);
             // Temporarily set ID to keep track of bundles that have had their discounts applied
             $discount->id = $metadataKey;
             // Add the bundle ID to the log to prevent an infinite loop
             $this->_bundleLog[$metadataKey] = $metadataKey;
             $this->get('basket')->addEntity('discounts', $discount);
         } catch (Exception\BundleValidationException $e) {
             if ($bundleExists) {
                 $this->get('http.session')->getFlashBag()->add('warning', $e->getMessage());
             }
             return false;
         }
     }
     return true;
 }
 /**
  * Listen to when an order has been completed and check to see whether the user that made the order has been
  * referred. If they have and the reward creation has triggered, it will then validate the order fulfills
  * any rules set by the constraints.
  *
  * If the referral is valid and fulfills the specifications of the reward configuration, a discount code will be
  * generated and an event will be fired. If for some reason a discount code not be generated, the referrer
  * will be informed that they are eligible for a discount but its generation was not successful, and that they
  * should get in touch with the vendor. The referral will be marked with an error status.
  *
  * @param OrderEvent $event
  */
 public function giveReward(OrderEvent $event)
 {
     $order = $event->getOrder();
     $referrals = $this->get('refer.referral.loader')->getByEmail($order->user->email, Statuses::PENDING);
     if (empty($referrals)) {
         return;
     }
     foreach ($referrals as $referral) {
         if ($referral->hasTriggered(OrderEvents::CREATE_COMPLETE)) {
             foreach ($referral->getRewardConfig()->getConstraints() as $constraint) {
                 // Don't bother checking minimum order if currency does not match
                 if ($constraint instanceof MinimumOrder && $order->currencyID !== $constraint->getCurrency()) {
                     continue;
                 }
                 if (false === $constraint->isValid($referral, $event)) {
                     return;
                 }
             }
             try {
                 $discount = $this->get('refer.discount.discount_builder')->build($referral);
                 $discount = $this->get('discount.create')->create($discount);
                 if ($discount->id) {
                     // Save again because the emails don't save on create.
                     $discount = $this->get('discount.edit')->save($discount);
                     $event = new DiscountCreateEvent();
                     $event->setReferral($referral);
                     $event->setDiscount($discount);
                     $this->get('event.dispatcher')->dispatch(DiscountRewardEvents::DISCOUNT_CREATE, $event);
                 } else {
                     throw new DiscountBuildException('Could not save new discount to database');
                 }
             } catch (DiscountBuildException $e) {
                 $this->get('refer.discount.failure_mailer')->report($referral, $e);
                 $referral->setStatus(Statuses::ERROR);
                 $this->get('refer.referral.edit')->save($referral);
             }
         }
     }
 }
 /**
  * @param Order\Order $order
  * @param Order\CancellationRefund $refund
  */
 public function __construct(Order\Order $order, Order\CancellationRefund $refund)
 {
     parent::__construct($order);
     $this->_refund = $refund;
 }
 /**
  * Alter analytics view in checkout if possible
  *
  * @param OrderEvent $event
  */
 public function switchAnalyticsCheckoutView(OrderEvent $event)
 {
     $provider = $this->get('analytics.provider');
     if (!$provider instanceof AnalyticsEditableProviderInterface) {
         return;
     }
     $viewRef = 'Message:Mothership:Ecommerce::analytics:' . $provider->getName();
     try {
         $this->get('templating.view_name_parser')->parse($viewRef);
     } catch (NotAcceptableHttpException $e) {
         return;
     }
     $parentView = $provider->getViewReference();
     $params = array_merge($provider->getViewParams(), ['order' => $event->getOrder(), 'parentView' => $parentView]);
     $provider->setViewReference($viewRef);
     $provider->setViewParams($params);
 }
 /**
  * Decrement the products.sales stat for each product ordered.
  *
  * @param  Event\Event $event
  */
 public function recordProductsSalesDeleted(Event\Event $event)
 {
     $dataset = $this->get('statistics')->get('products.sales');
     foreach ($event->getOrder()->getItemRows() as $unitID => $items) {
         $dataset->counter->decrement($unitID, count($items));
     }
 }
 /**
  * Set status of voucher items to received if e-vouchers are enabled
  *
  * @param Order\Event\Event $event
  */
 public function setVoucherItemStatus(Order\Event\Event $event)
 {
     if ($this->_eVouchersDisabled()) {
         return;
     }
     $vouchers = $this->_getVoucherItems($event->getOrder()->items);
     if (!empty($vouchers)) {
         $this->get('order.item.edit')->updateStatus($vouchers, Order\Statuses::RECEIVED);
     }
     if (count($vouchers) === count($event->getOrder()->items)) {
         $this->get('order.edit')->updateStatus($event->getOrder(), Order\Statuses::RECEIVED);
     }
 }
 public function calculateAllItemsTax(Event\Event $event)
 {
     foreach ($event->getOrder()->items as $item) {
         $this->_calculateTaxForItem($item);
     }
 }
 /**
  * Record the time it took since the order was created to complete
  * fulfillment.
  *
  * @param  Event\Event $event
  */
 public function recordFulfillmentTime(Event\Event $event)
 {
     $order = $event->getOrder();
     $fulfillmentTime = time() - $order->authorship->createdAt()->getTimestamp();
     $this->get('statistics')->get('fulfillment.time')->counter->set($order->id, $fulfillmentTime);
 }
 /**
  * Set the totals on the order as the last event before the order is created.
  *
  * @param Event $event The event object
  */
 public function setTotals(Event\Event $event)
 {
     $order = $event->getOrder();
     $order->updateTotals();
 }
 /**
  * Constructor.
  *
  * @param Order $order
  * @param Dispatch  $dispatch
  */
 public function __construct(Dispatch $dispatch, Order $order = null)
 {
     $order = $order ?: $dispatch->order;
     parent::__construct($order);
     $this->setDispatch($dispatch);
 }
 /**
  * If no status has been set on the order yet, set it to the default status
  * (awaiting dispatch).
  *
  * @param Event $event The event object
  */
 public function setDefaultStatus(Event\Event $event)
 {
     if (!$event->getOrder()->status) {
         $event->getOrder()->status = $this->get('order.statuses')->get(Statuses::AWAITING_DISPATCH);
     }
 }