/** * Updates or deletes dispatches when items of an order are cancelled. * Removes all cancelled items and updates the dispatch. * If all items have been cancelled, the dispatch is deleted. * * @param Event\TransactionalEvent $event Event */ public function updateDispatches(Event\TransactionalEvent $event) { $order = $event->getOrder(); $trans = $event->getTransaction(); $dispatchEdit = $this->get('order.dispatch.edit'); $dispatchDeleter = $this->get('order.dispatch.delete'); $dispatchEdit->setTransaction($trans); $dispatchDeleter->setTransaction($trans); foreach ($order->dispatches as $dispatch) { if ($dispatch->authorship->isDeleted()) { continue; } $updateNecessary = false; foreach ($dispatch->items as $item) { if (Statuses::CANCELLED === $item->status->code) { $dispatch->items->remove($item); $updateNecessary = true; } } if ($updateNecessary) { $dispatchEdit->update($dispatch); if (0 === $dispatch->items->count()) { $dispatchDeleter->delete($dispatch); } } } }
/** * Update the items' statuses to match their parent order's status, where * the order status is 'cancelled'. * * @param EventTransactionalEvent $event */ public function updateStatus(Event\TransactionalEvent $event) { $order = $event->getOrder(); if (Statuses::CANCELLED === $order->status->code) { $this->_itemEdit->setTransaction($event->getTransaction()); $this->_itemEdit->updateStatus($order->items->all(), Statuses::CANCELLED); } }
public function adjustStock(Event\TransactionalEvent $event) { $order = $event->getOrder(); $trans = $event->getTransaction(); $stockManager = $this->get('stock.manager'); $stockManager->setTransaction($trans); $stockManager->createWithRawNote(true); $stockManager->setReason($this->get('stock.movement.reasons')->get('new_order')); $trans->add("SET @STOCK_NOTE = CONCAT('Order #', ?i);", $order->id); $stockManager->setNote('@STOCK_NOTE'); $stockManager->setAutomated(true); foreach ($order->getItems() as $item) { $stockManager->decrement($item->getUnit(), $item->stockLocation); } }
/** * Dispatch the event to set the order's overall status. This is fired when * an item status changes. * * If the event results in a status code that is different to the order's * existing status code, it is updated. * * @param Event\TransactionalEvent $event The event object */ public function dispatchSetOrderStatusEvent(Event\TransactionalEvent $event) { $statusEvent = $event->getDispatcher()->dispatch(OrderEvents::SET_STATUS, new Event\SetOrderStatusEvent($event->getOrder())); $orderStatus = $statusEvent->getStatus(); $order = $statusEvent->getOrder(); // Skip if no status was set if (is_null($orderStatus)) { return; } // Skip if the status hasn't changed if ($orderStatus === $order->status->code) { return; } $edit = $this->get('order.edit'); $edit->setTransaction($event->getTransaction()); $edit->updateStatus($order, $orderStatus); }
/** * Creates a transaction with records for the order, all items and payments * * @param Event\Event $event event carrying information about order */ public function createOrderTransaction(Event\TransactionalEvent $event) { $order = $event->getOrder(); if ($order->status->code >= Statuses::AWAITING_DISPATCH || $order->status->code === Statuses::PAYMENT_PENDING) { $transaction = new Transaction(); $transaction->records->add($order); foreach ($order->items as $item) { $transaction->records->add($item); } foreach ($order->payments as $payment) { $transaction->records->add($payment); } // $transaction->type = // ($order->status->code === Statuses::PAYMENT_PENDING ? Types::CONTRACT_INITIATION : Types::ORDER); $transaction->type = Types::ORDER; $this->get('order.transaction.create')->setDbTransaction($event->getTransaction())->create($transaction); } }
/** * Delete an order by marking it as deleted in the database. * * @param Order $order The order to be deleted * * @return Order The order that was deleted, with the "delete" authorship data set */ public function delete(Order $order) { $order->authorship->delete(new DateTimeImmutable(), $this->_currentUser->id); $event = new Event\TransactionalEvent($order); $event->setTransaction($this->_trans); $order = $this->_eventDispatcher->dispatch(Events::DELETE_START, $event)->getOrder(); $this->_trans->run(' UPDATE order_summary SET deleted_at = :at?d, deleted_by = :by?in WHERE order_id = :id?i ', array('at' => $order->authorship->deletedAt(), 'by' => $order->authorship->deletedBy(), 'id' => $order->id)); $event = new Event\TransactionalEvent($order); $event->setTransaction($this->_trans); $order = $this->_eventDispatcher->dispatch(Events::DELETE_END, $event)->getOrder(); return $order; }
public function updateStatus(Order $order, $statusCode) { if (!$this->_statuses->exists($statusCode)) { throw new \InvalidArgumentException(sprintf('Order status `%s` does not exist', $statusCode)); } $status = $this->_statuses->get($statusCode); // Skip if the item is already at this status if ($status->code === $order->status->code) { return false; } $order->authorship->update(new DateTimeImmutable(), $this->_currentUser->id); $this->_query->run(' UPDATE order_summary SET status_code = :status?i, updated_at = :updatedAt?i, updated_by = :updatedBy?in WHERE order_id = :id?i ', array('id' => $order->id, 'status' => $status->code, 'updatedAt' => $order->authorship->updatedAt(), 'updatedBy' => $order->authorship->updatedBy())); if ($status->code === Statuses::CANCELLED) { $this->_query->run('UPDATE `order_shipping` SET `status_code` = :status?i WHERE `order_id` = :id?i', ['id' => $order->id, 'status' => $status->code]); } $order->status = clone $status; $event = new Event\TransactionalEvent($order); $event->setTransaction($this->_query); $order = $this->_eventDispatcher->dispatch(Events::STATUS_CHANGE, $event)->getOrder(); if (!$this->_transOverridden) { $this->_query->commit(); } return $this->_eventDispatcher->dispatch(Events::EDIT, new Event\Event($order))->getOrder(); }
/** * Constructor. * * @param Order $order * @param EntityInterface $entity */ public function __construct(Order $order, EntityInterface $entity) { parent::__construct($order); $this->setEntity($entity); }
public function create(Order $order) { $event = new Event\TransactionalEvent($order); $event->setTransaction($this->_trans); $order = $this->_eventDispatcher->dispatch(Events::CREATE_START, $event)->getOrder(); $validation = $this->_eventDispatcher->dispatch(Events::CREATE_VALIDATE, new Event\ValidateEvent($order)); if ($validation->hasErrors()) { throw new \InvalidArgumentException(sprintf('Cannot create order: %s', implode(', ', $validation->getErrors()))); } if (!$order->authorship->createdAt()) { $order->authorship->create(new DateTimeImmutable(), $this->_currentUser->id); } $this->_trans->add(' INSERT INTO order_summary SET created_at = :createdAt?d, created_by = :createdBy?in, status_code = :status?i, user_id = :userID?in, user_email = :userEmail?sn, type = :type?sn, locale = :locale?s, taxable = :taxable?b, currency_id = :currencyID?s, conversion_rate = :conversionRate?f, product_net = :productNet?f, product_discount = :productDiscount?f, product_tax = :productTax?f, product_gross = :productGross?f, total_net = :totalNet?f, total_discount = :totalDiscount?f, total_tax = :totalTax?f, total_gross = :totalGross?f ', array('createdAt' => $order->authorship->createdAt(), 'createdBy' => $order->authorship->createdBy(), 'userID' => $order->user ? $order->user->id : null, 'userEmail' => $order->user ? $order->user->email : null, 'status' => $order->status->code, 'type' => $order->type, 'locale' => $order->locale, 'taxable' => $order->taxable, 'currencyID' => $order->currencyID, 'conversionRate' => $order->conversionRate, 'productNet' => $order->productNet, 'productDiscount' => $order->productDiscount, 'productTax' => $order->productTax, 'productGross' => $order->productGross, 'totalNet' => $order->totalNet, 'totalDiscount' => $order->totalDiscount, 'totalTax' => $order->totalTax, 'totalGross' => $order->totalGross)); $this->_trans->setIDVariable('ORDER_ID'); $order->id = '@ORDER_ID'; $this->_trans->add(' INSERT INTO order_shipping SET order_id = :orderID?i, list_price = :listPrice?f, net = :net?f, discount = :discount?f, tax = :tax?f, tax_rate = :taxRate?f, gross = :gross?f, name = :name?sn, display_name = :display_name?sn ', array('orderID' => $order->id, 'listPrice' => $order->shippingListPrice, 'net' => $order->shippingNet, 'discount' => $order->shippingDiscount, 'tax' => $order->shippingTax, 'taxRate' => $order->shippingTaxRate, 'gross' => $order->shippingGross, 'name' => $order->shippingName, 'display_name' => $order->shippingDisplayName)); // Insert metadata foreach ($order->metadata as $key => $value) { $this->_trans->add(' INSERT INTO order_metadata SET `order_id` = :orderID?i, `key` = :key?s, `value` = :value?sn ', array('orderID' => $order->id, 'key' => $key, 'value' => $value)); } foreach ($order->getEntities() as $name => $collection) { if (count($collection) > 0 && !array_key_exists($name, $this->_entityCreators)) { throw new \LogicException(sprintf('Creator for `%s` order entity not set on order creator', $name)); } foreach ($collection as $entity) { $entity->order = $order; // Create the entities with the same authorship data as the order if (isset($entity->authorship) && $entity->authorship instanceof Authorship && !$entity->authorship->createdAt()) { $entity->authorship->create($order->authorship->createdAt(), $order->authorship->createdBy()); } $this->_entityCreators[$name]->create($entity); } } // Insert item tax rates $tokens = []; $inserts = []; foreach ($order->getShippingTaxes() as $type => $rate) { $tokens[] = '(?i, ?s, ?f, ?f)'; $inserts[] = $order->id; $inserts[] = $type; $inserts[] = $rate; $inserts[] = $order->shippingNet * $rate / 100; } if ($inserts) { $this->_trans->add("INSERT INTO\n\t\t\t\t\t`order_shipping_tax` (`order_id`, `tax_type`, `tax_rate`, `tax_amount`)\n\t\t\t\tVALUES " . implode(',', $tokens), $inserts); } // Fire the "create end" event before committing the transaction $event = new Event\TransactionalEvent($order); $event->setTransaction($this->_trans); $this->_eventDispatcher->dispatch(Events::CREATE_END, $event); $order = $event->getOrder(); // add CREATE_COMPLETE event to when transaction is committed $loader = $this->_loader; $this->_trans->attachEvent(Events::CREATE_COMPLETE, function ($trans) use($loader) { return new Event\Event($loader->getByID($trans->getIDVariable('ORDER_ID'))); }); // @todo ideally we want to listen to CREATE_COMPLETE // check if $event->getOrder()->id == $sqlVariableThing // then set that as the return value if (!$this->_transOverridden) { $this->_trans->commit(); $order = $this->_loader->getByID($this->_trans->getIDVariable('ORDER_ID')); } return $order; }
/** * Update the status of an item or items. * * @param Item|Collection|array $items Item, array of items or collection * of items * @param int $statusCode Status code to set * * @return Edit Returns $this for chainability * * @throws \InvalidArgumentException If the item status supplied is not * set on the status collection * @throws \InvalidArgumentException If no valid Item instances are passed * @throws \InvalidArgumentException If a non-falsey value that is not an * instance of Item is passed as an item */ public function updateStatus($items, $statusCode) { if (!$this->_statuses->exists($statusCode)) { throw new \InvalidArgumentException(sprintf('Order item status `%s` does not exist', $statusCode)); } $status = $this->_statuses->get($statusCode); if (!is_array($items) && !$items instanceof Collection) { $items = array($items); } // Filter out any falsey values $items = $items instanceof Collection ? $items->all() : $items; $items = array_filter($items); $orders = []; // Throw exception if we don't have any items if (empty($items)) { throw new \InvalidArgumentException('No items passed to `updateStatus()`'); } foreach ($items as $key => $item) { if (!$item instanceof Item) { $type = gettype($item); if ($type == 'object') { $type = get_class($item); } throw new \InvalidArgumentException(sprintf('Unexpected value: expected order item instance - "' . $type . '"')); } // Skip if the item is already at this status if ($status->code === $item->status->code) { continue; } // Get instance of item status (so we have authorship info) $status = new Status\Status($status->code, $status->name); $status->authorship->create(new DateTimeImmutable(), $this->_currentUser->id); $this->_query->add(' INSERT INTO order_item_status SET order_id = :orderID?i, item_id = :itemID?i, status_code = :status?i, created_at = :createdAt?i, created_by = :createdBy?in ', array('orderID' => $item->order->id, 'itemID' => $item->id, 'status' => $status->code, 'createdAt' => $status->authorship->createdAt(), 'createdBy' => $status->authorship->createdBy())); $item->status = $status; // Collect the order if it hasn't been collected yet if (!array_key_exists($item->order->id, $orders)) { $orders[$item->order->id] = $item->order; } } // Dispatch an event for each individual order foreach ($orders as $order) { $event = new Event\TransactionalEvent($order); $event->setTransaction($this->_query); $this->_eventDispatcher->dispatch(OrderEvents::ITEM_STATUS_CHANGE, $event); } if (!$this->_transOverridden) { $this->_query->commit(); } return $this; }