/**
  * Update the status of the returned item if there is one to whatever the
  * status was before it was returned.
  *
  * Currently this just chooses the status before the current one, but it
  * could be more robust.
  *
  * @todo Look into making this more robust, by knowing how many steps to
  *       take back in the status history to get to just before the return
  *       started.
  *
  * @param  OrderTransaction\Event\TransactionalEvent $event
  */
 public function revertReturnedItemStatus(OrderTransaction\Event\TransactionalEvent $event)
 {
     $transaction = $event->getTransaction();
     // Skip if the transaction is not a return transaction
     if (Types::ORDER_RETURN !== $transaction->type) {
         return false;
     }
     $itemEdit = $this->get('order.item.edit');
     $itemEdit->setTransaction($event->getDbTransaction());
     foreach ($transaction->records->getByType(OrderReturn::RECORD_TYPE) as $return) {
         // Skip if the return was not for an order (i.e. it was a standalone return)
         if (!$return->item->order) {
             return false;
         }
         $item = $return->item->orderItem;
         $history = $this->get('order.item.status.loader')->getHistory($item);
         // Skip if there was not more than 2 statuses on the item
         if (count($history) < 2) {
             continue;
         }
         // Get the status before the current one
         $previousStatus = array_shift($history);
         $previousStatus = array_shift($history);
         $itemEdit->updateStatus($item, $previousStatus->code);
     }
 }
    /**
     * Creates the transaction.
     * If a DB\Transaction has been explicitly set, adds the Transaction to the
     * DB\Transaction. Otherwise commits $_query.
     *
     * @param  Transaction $transaction transaction to be created
     *
     * @return Transaction              if transaction wasn't overridden
     *                                  re-loaded $transaction, otherwise just
     *                                  $transaction
     */
    public function create(Transaction $transaction)
    {
        // Set create authorship data if not already set
        if (!$transaction->authorship->createdAt()) {
            $transaction->authorship->create(new DateTimeImmutable(), $this->_currentUser->id);
        }
        $event = new Event\TransactionalEvent($transaction);
        $event->setDbTransaction($this->_query);
        $transaction = $this->_eventDispatcher->dispatch(Events::CREATE_START, $event)->getTransaction();
        $this->_validate($transaction);
        $this->_query->run('
			INSERT INTO
				transaction
			SET
				created_at     = :createdAt?d,
				created_by     = :createdBy?in,
				type           = :type?s
		', array('createdAt' => $transaction->authorship->createdAt(), 'createdBy' => $transaction->authorship->createdBy(), 'type' => $transaction->type));
        $sqlVariable = 'TRANSACTION_ID_' . uniqid();
        $this->_query->setIDVariable($sqlVariable);
        $transaction->id = '@' . $sqlVariable;
        $this->_createRecords($transaction);
        $this->_createAttributes($transaction);
        $loader = $this->_loader;
        $this->_query->attachEvent(Events::CREATE_COMPLETE, function ($dbTrans) use($loader, $sqlVariable) {
            return new Event\Event($loader->getByID($dbTrans->getIDVariable($sqlVariable)));
        });
        if (!$this->_transOverridden) {
            $this->_query->commit();
        }
        return $transaction;
    }
    /**
     * Voids the given transaction.
     *
     * @param  Transaction $transaction Transaction to be voided
     *
     * @return Transaction              The voided transaction
     *
     * @throws \InvalidArgumentException If transaction is already voided
     */
    public function void(Transaction $transaction)
    {
        if ($transaction->isVoided()) {
            throw new \InvalidArgumentException('Transaction has already been voided.');
        }
        $transaction->voidedAt = new DateTimeImmutable();
        $transaction->voidedBy = $this->_user->id;
        $result = $this->_query->run('
			UPDATE
				transaction
			SET
				voided_at = :at?d,
				voided_by = :by?in
			WHERE
				transaction_id = :id?i
		', ['at' => $transaction->voidedAt, 'by' => $transaction->voidedBy, 'id' => $transaction->id]);
        $event = new Event\TransactionalEvent($transaction);
        $event->setDbTransaction($this->_query);
        $transaction = $this->_eventDispatcher->dispatch(Events::VOID, $event)->getTransaction();
        if (!$this->_transOverridden) {
            $this->_query->commit();
        }
        return $transaction;
    }
 /**
  * Create a stock movement to put all items in a transaction that is being
  * voided back into stock in the stock location they were purchased from.
  *
  * @param Transaction\Event\TransactionalEvent $event
  */
 public function returnItemsToStock(Transaction\Event\TransactionalEvent $event)
 {
     $transaction = $event->getTransaction();
     $stockManager = $this->get('stock.manager');
     $stockManager->setTransaction($event->getDbTransaction());
     $stockManager->createWithRawNote(true);
     $stockManager->setReason($this->get('stock.movement.reasons')->get('void_transaction'));
     $event->getDbTransaction()->add("\n\t\t\tSET @STOCK_NOTE = CONCAT('Void transaction #', ?i)\n\t\t", $transaction->id);
     $stockManager->setNote('@STOCK_NOTE');
     $stockManager->setAutomated(true);
     foreach ($transaction->records->getByType(Item\Item::RECORD_TYPE) as $item) {
         $stockManager->increment($item->getUnit(), $item->stockLocation);
     }
 }