/**
     * Creates a refund.
     *
     * Dispatches Order\Events::ENTITY_CREATE and Order\Events::ENTITY_CREATE_END
     * events.
     *
     * Commits the transaction if $_transOverridden is false.
     *
     * @param  Refund $refund Refund to be created
     *
     * @return Refund          The created refund, reloaded if the transaction
     *                          was not overridden
     */
    public function create(Refund $refund)
    {
        $this->_validate($refund);
        $event = new Order\Event\EntityEvent($refund->order, $refund);
        $event->setTransaction($this->_trans);
        $refund = $this->_eventDispatcher->dispatch(Order\Events::ENTITY_CREATE, $event)->getEntity();
        if (!$refund->refund->id) {
            $this->_refundCreate->create($refund->refund);
        }
        $this->_trans->run('
			INSERT INTO
				order_refund
			SET
				order_id  = :orderID?i,
				refund_id = :refundID?i
		', ['orderID' => $refund->order->id, 'refundID' => $refund->id]);
        $event = new Order\Event\EntityEvent($refund->order, $refund);
        $event->setTransaction($this->_trans);
        $refund = $this->_eventDispatcher->dispatch(Order\Events::ENTITY_CREATE_END, $event)->getEntity();
        if (!$this->_transOverridden) {
            $this->_trans->commit();
            return $this->_loader->getByID($this->_trans->getIDVariable(str_replace('@', '', $refund->id)));
        }
        return $refund;
    }
    public function create(Note $note)
    {
        $event = new Order\Event\EntityEvent($note->order, $note);
        if ($this->_query instanceof DB\Transaction) {
            $event->setTransaction($this->_query);
        }
        $note = $this->_eventDispatcher->dispatch(Order\Events::ENTITY_CREATE, $event)->getEntity();
        // Set create authorship data if not already set
        if (!$note->authorship->createdAt()) {
            $note->authorship->create(new DateTimeImmutable(), $this->_currentUser->id);
        }
        $result = $this->_query->run('
			INSERT INTO
				order_note
			SET
				order_id          = :orderID?i,
				created_at        = :createdAt?i,
				created_by        = :createdBy?in,
				note              = :note?s,
				customer_notified = :customerNotified?b,
				raised_from       = :raisedFrom?sn
		', array('orderID' => $note->order->id, 'createdAt' => $note->authorship->createdAt(), 'createdBy' => $note->authorship->createdBy(), 'note' => $note->note, 'customerNotified' => $note->customerNotified, 'raisedFrom' => $note->raisedFrom));
        if ($this->_query instanceof DB\Transaction) {
            return $note;
        }
        return $this->_loader->getByID($result->id(), $note->order);
    }
 /**
  * Generate vouchers for any items added to an order that are voucher
  * products.
  *
  * The product ID for the item must be listed in the "product-ids" config
  * element in the "voucher" group.
  *
  * The voucher amount is set to the *list price* of the item, not the net
  * or gross amount.
  *
  * The voucher ID is then set as the personalisation key "voucher_id" on the
  * relevant item.
  *
  * The queries for adding the voucher are added to the same transaction as
  * the item creation queries.
  *
  * @param Order\Event\EntityEvent $event The event object
  */
 public function generateForSales(Order\Event\EntityEvent $event)
 {
     $item = $event->getEntity();
     if (!$item instanceof Order\Entity\Item\Item) {
         return false;
     }
     $isVoucher = $item->getProduct()->getType()->getName() === 'voucher';
     if (false === $isVoucher) {
         $this->_loadProductIDs();
         // Skip if no voucher product IDs are defined in the config
         if (!$this->_voucherProductIDs || empty($this->_voucherProductIDs)) {
             return false;
         }
         if (!in_array($item->productID, $this->_voucherProductIDs)) {
             return false;
         }
     }
     $unit = $item->getUnit();
     $voucher = new Voucher();
     if ($unit && isset($unit->options['currency']) && isset($unit->options['amount'])) {
         $voucher->currencyID = $unit->options['currency'];
         $voucher->amount = $unit->options['amount'];
     } else {
         $voucher->currencyID = $item->order->currencyID;
         $voucher->amount = $item->actualPrice;
     }
     $voucher->id = $this->_idGenerator->generate();
     $voucher->purchasedAsItem = $item;
     if ($item->order->user && !$item->order->user instanceof AnonymousUser) {
         $voucher->authorship->create(new DateTimeImmutable(), $item->order->user->id);
     }
     $this->_create->setTransaction($event->getTransaction());
     $this->_create->create($voucher);
     $item->personalisation->voucher_id = $voucher->id;
 }
    /**
     * Creates a payment.
     *
     * Dispatches Order\Events::ENTITY_CREATE and Order\Events::ENTITY_CREATE_END
     * events.
     *
     * Commits the transaction if $_transOverridden is false.
     *
     * @param  Payment $payment Payment to be created
     *
     * @return Payment          The created payment, reloaded if the transaction
     *                          was not overridden
     */
    public function create(Payment $payment)
    {
        $this->_validate($payment);
        $event = new Order\Event\EntityEvent($payment->order, $payment);
        $event->setTransaction($this->_trans);
        $payment = $this->_eventDispatcher->dispatch(Order\Events::ENTITY_CREATE, $event)->getEntity();
        if (!$payment->payment->id) {
            $this->_paymentCreate->create($payment->payment);
        }
        $this->_trans->run('
			INSERT INTO
				order_payment
			SET
				order_id   = :orderID?i,
				payment_id = :paymentID?i
		', ['orderID' => $payment->order->id, 'paymentID' => $payment->id]);
        $event = new Order\Event\EntityEvent($payment->order, $payment);
        $event->setTransaction($this->_trans);
        $payment = $this->_eventDispatcher->dispatch(Order\Events::ENTITY_CREATE_END, $event)->getEntity();
        if (!$this->_transOverridden) {
            $this->_trans->commit();
            return $this->_loader->getByID($this->_trans->getIDVariable(str_replace('@', '', $payment->id)));
        }
        return $payment;
    }
 /**
  * Send a customer a notification.
  *
  * @param Event\EntityEvent $event
  */
 public function sendCustomerNotification(Event\EntityEvent $event)
 {
     $note = $event->getEntity();
     if (!$note instanceof Note or !$note->customerNotified) {
         return false;
     }
     $factory = $this->get('mail.factory.order.note.notification')->set('order', $event->getOrder())->set('note', $note);
     $this->get('mail.dispatcher')->send($factory->getMessage());
 }
 /**
  * Creates a transaction for contract payments when a payment is added to a
  * contract.
  *
  * @param  Event\EntityEvent $event event carrying information about created
  *                                  entity
  */
 public function createPaymentTransaction(Event\EntityEvent $event)
 {
     $payment = $event->getEntity();
     $order = $event->getOrder();
     if ($payment instanceof Payment && $order->status->code === Statuses::PAYMENT_PENDING && null !== $order->id) {
         $transaction = new Transaction();
         $transaction->records->add($payment);
         $transaction->type = Types::CONTRACT_PAYMENT;
         $this->get('order.transaction.create')->setDbTransaction($event->getTransaction())->create($transaction);
     }
 }
 /**
  * Clears the "id" property on the `Payment` entity before it is created.
  *
  * This is because the "id" is sometimes temporarily filled with something
  * else as a way to identify the payment as unique. For example, voucher
  * payments have the voucher ID set as the payment ID during assembly.
  *
  * @param  EntityEvent $event
  */
 public function removeTemporaryIDs(EntityEvent $event)
 {
     $entity = $event->getEntity();
     if (!$entity instanceof Payment) {
         return false;
     }
     // Skip if the ID is a MySQL variable. We need this!
     if ('@' === substr($entity->id, 0, 1)) {
         return false;
     }
     $entity->id = null;
 }
    public function create(Item $item)
    {
        $event = new Order\Event\EntityEvent($item->order, $item);
        $event->setTransaction($this->_query);
        $item = $this->_eventDispatcher->dispatch(Order\Events::ENTITY_CREATE, $event)->getEntity();
        // Set create authorship data if not already set
        if (!$item->authorship->createdAt()) {
            $item->authorship->create(new DateTimeImmutable(), $this->_currentUser->id);
        }
        $this->_validate($item);
        $this->_query->add('
			INSERT INTO
				order_item
			SET
				order_id          = :orderID?i,
				created_at        = :createdAt?d,
				created_by        = :createdBy?in,
				list_price        = :listPrice?f,
				actual_price      = :actualPrice?f,
				base_price        = :basePrice?f,
				net               = :net?f,
				discount          = :discount?f,
				tax               = :tax?f,
				tax_rate          = :taxRate?f,
				product_tax_rate  = :productTaxRate?f,
				gross             = :gross?f,
				rrp               = :rrp?fn,
				tax_strategy      = :taxStrategy?sn,
				product_id        = :productID?in,
				product_name      = :productName?sn,
				unit_id           = :unitID?in,
				unit_revision     = :unitRevision?in,
				sku               = :sku?sn,
				barcode           = :barcode?sn,
				options           = :options?sn,
				brand             = :brand?sn,
				weight_grams      = :weight?in,
				stock_location    = :stockLocation?s
		', array('orderID' => $item->order->id, 'createdAt' => $item->authorship->createdAt(), 'createdBy' => $item->authorship->createdBy(), 'listPrice' => $item->listPrice, 'actualPrice' => $item->actualPrice, 'basePrice' => $item->basePrice, 'net' => $item->net, 'discount' => $item->discount, 'tax' => $item->tax, 'taxRate' => $item->taxRate, 'productTaxRate' => $item->productTaxRate, 'gross' => $item->gross, 'rrp' => $item->rrp, 'taxStrategy' => $item->taxStrategy, 'productID' => $item->productID, 'productName' => $item->productName, 'unitID' => $item->unitID, 'unitRevision' => $item->unitRevision, 'sku' => $item->sku, 'barcode' => $item->barcode, 'options' => $item->options, 'brand' => $item->brand, 'weight' => $item->weight, 'stockLocation' => $item->stockLocation->name));
        $sqlVariable = 'ITEM_ID_' . uniqid();
        $this->_query->setIDVariable($sqlVariable);
        $item->id = '@' . $sqlVariable;
        // Set the initial status, if defined
        if ($item->status) {
            if (!$item->status->authorship->createdAt()) {
                $item->status->authorship->create($item->authorship->createdAt(), $item->authorship->createdBy());
            }
            $this->_query->add('
				INSERT INTO
					order_item_status
				SET
					order_id    = :orderID?i,
					item_id     = :itemID?i,
					status_code = :code?i,
					created_at  = :createdAt?d,
					created_by  = :createdBy?in
			', array('orderID' => $item->order->id, 'itemID' => $item->id, 'code' => $item->status->code, 'createdAt' => $item->status->authorship->createdAt(), 'createdBy' => $item->status->authorship->createdBy()));
        }
        $event = new Order\Event\EntityEvent($item->order, $item);
        $event->setTransaction($this->_query);
        $item = $this->_eventDispatcher->dispatch(Events::CREATE_PRE_PERSONALISATION_INSERTS, $event)->getEntity();
        // Set personalisation data, if defined
        foreach ($item->personalisation as $name => $value) {
            $this->_query->add('
				INSERT INTO
					order_item_personalisation
				SET
					item_id = :itemID?i,
					name    = :name?s,
					value   = :value?sn
			', array('itemID' => $item->id, 'name' => $name, 'value' => $value));
        }
        // Insert item tax rates
        $tokens = [];
        $inserts = [];
        foreach ($item->getTaxRates() as $type => $rate) {
            $tokens[] = '(?i, ?s, ?f, ?f)';
            $inserts[] = $item->id;
            $inserts[] = $type;
            $inserts[] = $rate;
            $inserts[] = $item->net * $rate / 100;
        }
        if ($inserts) {
            $this->_query->add("INSERT INTO \n\t\t\t\t\t`order_item_tax` (`item_id`, `tax_type`, `tax_rate`, `tax_amount`) \n\t\t\t\tVALUES " . implode(',', $tokens), $inserts);
        }
        // If the query was not in a transaction, return the re-loaded item
        if (!$this->_transOverridden) {
            $this->_query->commit();
            return $this->_loader->getByID($this->_query->getIDVariable($sqlVariable), $item->order);
        }
        return $item;
    }
 /**
  * Calculate the gross, tax and net amounts for each item in an order before
  * it gets created in the database.
  *
  * This event is skipped if the order is not taxable.
  *
  * @param EntityEvent $event The event object
  */
 public function calculateTax(Event\EntityEvent $event)
 {
     $item = $event->getEntity();
     if (!$item instanceof Item) {
         return false;
     }
     $this->_calculateTaxForItem($item);
 }