/** * "Close" the order for modifications and fix its state * * 1) fix current product prices and total (so the total doesn't change if product prices change) * 2) save created shipments * * @return CustomerOrder New order instance containing wishlist items */ public function finalize($options = array()) { if ($this->isFinalized->get() && empty($options['allowRefinalize'])) { return; } self::beginTransaction(); $this->event('before-finalize'); $this->loadAll(); $currency = $this->getCurrency(); foreach ($this->getShipments() as $shipment) { if ($shipment->isExistingRecord()) { $shipment->deleteRecordSet('ShipmentTax', new ARDeleteFilter()); } // clone shipping addresses if ($shipment->shippingAddress->get()) { $shippingAddress = clone $shipment->shippingAddress->get(); $shippingAddress->save(); $shipment->shippingAddress->set($shippingAddress); } $shipment->order->set($this); $shipment->save(); } $reserveProducts = self::getApplication()->isInventoryTracking(); foreach ($this->getShoppingCartItems() as $item) { if (empty($options['customPrice'])) { $item->price->set($item->getSubTotalBeforeTax() / $item->getCount()); } $item->name->set($item->getProduct()->getParent()->name->get()); $item->setValueByLang('name', 'sku', $item->getProduct()->sku->get()); $item->save(); // create sub-items for bundled products if ($item->getProduct()->isBundle()) { foreach ($item->getProduct()->getBundledProducts() as $bundled) { $bundledItem = OrderedItem::getNewInstance($this, $bundled->relatedProduct->get(), $bundled->getCount()); $bundledItem->parent->set($item); $bundledItem->save(); } } // reserve products if inventory is enabled if ($reserveProducts) { $item->reserve(); $item->save(); } } if (!$this->shippingAddress->get() && $this->user->get() && $this->user->get()->defaultShippingAddress->get() && $this->isShippingRequired()) { $this->shippingAddress->set($this->user->get()->defaultShippingAddress->get()->userAddress->get()); } if (!$this->billingAddress->get() && $this->user->get() && $this->user->get()->defaultBillingAddress->get()) { $this->billingAddress->set($this->user->get()->defaultBillingAddress->get()->userAddress->get()); } // clone billing/shipping addresses if (!$this->isFinalized->get()) { foreach (array('billingAddress', 'shippingAddress') as $address) { if ($this->{$address}->get()) { $this->{$address}->get()->load(); $this->{$address}->get()->getSpecification(); $cloned = clone $this->{$address}->get(); $cloned->save(); $cloned->loadEav(); $this->{$address}->set($cloned); } } } // move wish list items to a separate order if ($this->getWishListItems()) { $wishList = CustomerOrder::getNewInstance($this->user->get()); foreach ($this->getWishListItems() as $item) { $wishList->addItem($item); } $wishList->save(); } else { $wishList = null; } // set order total $this->totalAmount->set($this->getTotal(true)); // save shipment taxes foreach ($this->shipments as $shipment) { $shipment->save(); } // save discounts foreach ($this->orderDiscounts as $discount) { $discount->save(); } // @todo: remove the 0.99 multiplicator for currency conversion "tolerance" (a cent going missing when converting amounts between currencies back and forth) if (round($this->totalAmount->get(), 2) * 0.99 <= round($this->getPaidAmount(), 2)) { $this->isPaid->set(true); } $this->dateCompleted->set(new ARSerializableDateTime()); $this->isFinalized->set(true); // @todo: fix order total calculation $shipments = $this->shipments; unset($this->shipments); if (!$this->invoiceNumber->get()) { $generator = InvoiceNumberGenerator::getGenerator($this); $saved = false; while (!$saved) { try { $this->invoiceNumber->set($generator->getNumber()); $this->save(); $saved = true; } catch (SQLException $e) { } } } $this->event('after-finalize'); self::commit(); // @todo: see above $this->shipments = $shipments; // force updating array representation $this->resetArrayData(); return $wishList; }
/** * "Close" the order for modifications and fix its state * * 1) fix current product prices and total (so the total doesn't change if product prices change) * 2) save created shipments * * @return CustomerOrder New order instance containing wishlist items */ public function finalize($options = array()) { $rebillsLeft = 0; if ($this->isFinalized->get() && empty($options['allowRefinalize'])) { return; } self::beginTransaction(); $this->event('before-finalize'); $currency = $this->getCurrency(); $this->loadAll(); foreach ($this->getShipments() as $shipment) { if ($shipment->isExistingRecord()) { $shipment->deleteRecordSet('ShipmentTax', new ARDeleteFilter()); } $shipment->order->set($this); $shipment->save(); // clone shipping addresses if ($shipment->shippingAddress->get()) { $shippingAddress = clone $shipment->shippingAddress->get(); $shippingAddress->save(); $shipment->shippingAddress->set($shippingAddress); } } $reserveProducts = self::getApplication()->isInventoryTracking(); $rebillsLeft = 0; $groupedRebillsLeft = array(); $isFirstOrder = !$this->parentID->get(); foreach ($this->getShoppingCartItems() as $item) { // workround for failing tests. //if (!empty($options['customPrice'])) //{ $item->price->set($item->getSubTotalBeforeTax() / $item->getCount()); //} $item->name->set($item->getProduct()->getParent()->name->get()); $item->setValueByLang('name', 'sku', $item->getProduct()->sku->get()); $item->save(); // create sub-items for bundled products if ($item->getProduct()->isBundle()) { foreach ($item->getProduct()->getBundledProducts() as $bundled) { $bundledItem = OrderedItem::getNewInstance($this, $bundled->relatedProduct->get(), $bundled->getCount()); $bundledItem->parent->set($item); $bundledItem->save(); } } // reserve products if inventory is enabled if ($reserveProducts) { $item->reserve(); $item->save(); } if ($isFirstOrder) { $ri = RecurringItem::getInstanceByOrderedItem($item); if ($ri && $ri->isExistingRecord()) { $rebillCount = $ri->rebillCount->get(); // also here recurring item grouping $key = sprintf('%s_%s_%s', $ri->periodType->get(), $ri->periodLength->get(), $rebillCount === null ? 'NULL' : $rebillCount); if ($rebillCount !== null) { $groupedRebillsLeft[$key] = $rebillCount; } else { $groupedRebillsLeft[$key] = -1; // -1 means infinite rebill count } $this->isRecurring->set(true); // orders with at least one recurring billing plan must have isRecurring flag, if already not set. } } else { $rparentItem = $item->recurringParentID->get(); if ($rparentItem) { $ri = RecurringItem::getInstanceByOrderedItem($rparentItem, true); $ri->reload(); // if was bulk update, then cached data are outdated. if ($ri && $ri->isExistingRecord()) { // are RecurringItems grouped? // probably yes.. $rebillsLeft = $ri->rebillCount->get() - $ri->processedRebillCount->get(); } } } } if ($isFirstOrder) { foreach ($groupedRebillsLeft as $value) { if ($value == -1) { $rebillsLeft = -1; break; } else { $rebillsLeft += $value; } } } if (!$this->shippingAddress->get() && $this->user->get() && $this->user->get()->defaultShippingAddress->get() && $this->isShippingRequired()) { $this->shippingAddress->set($this->user->get()->defaultShippingAddress->get()->userAddress->get()); } if (!$this->billingAddress->get() && $this->user->get() && $this->user->get()->defaultBillingAddress->get()) { $this->billingAddress->set($this->user->get()->defaultBillingAddress->get()->userAddress->get()); } // clone billing/shipping addresses if (!$this->isFinalized->get()) { foreach (array('billingAddress', 'shippingAddress') as $address) { if ($this->{$address}->get()) { $this->{$address}->get()->load(); $this->{$address}->get()->getSpecification(); $cloned = clone $this->{$address}->get(); $cloned->save(); $cloned->loadEav(); $this->{$address}->set($cloned); } } } // move wish list items to a separate order if ($this->getWishListItems()) { $wishList = CustomerOrder::getNewInstance($this->user->get()); foreach ($this->getWishListItems() as $item) { $wishList->addItem($item); } $wishList->save(); } else { $wishList = null; } // set order total $this->totalAmount->set($this->getTotal(true)); // save shipment taxes foreach ($this->shipments as $shipment) { $shipment->save(); } // save discounts foreach ($this->orderDiscounts as $discount) { $discount->save(); } // @todo: remove the 0.99 multiplicator for currency conversion "tolerance" (a cent going missing when converting amounts between currencies back and forth) if (round($this->totalAmount->get(), 2) * 0.99 <= round($this->getPaidAmount(), 2)) { $this->isPaid->set(true); } $this->dateCompleted->set(new ARSerializableDateTime()); $this->isFinalized->set(true); // @todo: fix order total calculation $shipments = $this->shipments; unset($this->shipments); if (!$this->invoiceNumber->get()) { $generator = InvoiceNumberGenerator::getGenerator($this); $saved = false; while (!$saved) { try { $this->invoiceNumber->set($generator->getNumber()); $this->save(); $saved = true; } catch (SQLException $e) { } } } if ($this->isRecurring->get()) { $changed = false; if (!strlen($this->startDate->get())) { $this->startDate->set(date('Y-m-d H:i:s', time())); $changed = true; } if ($rebillsLeft != $this->rebillsLeft->get()) { $this->rebillsLeft->set($rebillsLeft); $changed = true; } if ($changed) { $this->save(); } } $this->event('after-finalize'); self::commit(); // @todo: see above $this->shipments = $shipments; // force updating array representation $this->resetArrayData(); return $wishList; }
public function create() { $request = $this->getRequest(); $query = $request->get('query'); if (strlen($query)) { $products = $this->getProductsFromSearchQuery($query); } else { $products = new ARSet(); $products->add(Product::getInstanceById((int) $this->request->get('productID'), true)); } $saveResponse = array('errors' => array(), 'items' => array()); $composite = new CompositeJSONResponse(); $order = CustomerOrder::getInstanceByID((int) $this->request->get('orderID'), true); $order->loadAll(); foreach ($products as $product) { if ($product->isDownloadable()) { $shipment = $order->getDownloadShipment(); } else { if ((int) $this->request->get('shipmentID')) { $shipment = Shipment::getInstanceById('Shipment', (int) $this->request->get('shipmentID'), true, array('Order' => 'CustomerOrder', 'ShippingService', 'ShippingAddress' => 'UserAddress', 'Currency')); } } if (empty($shipment)) { $shipment = $order->getShipments()->get(0); } if (!$shipment) { $shipment = Shipment::getNewInstance($order); } if (!$shipment->order->get()) { $shipment->order->set($order); } $history = new OrderHistory($order, $this->user); $existingItem = false; foreach ($shipment->getItems() as $item) { if ($item->getProduct() === $product) { if (!$product->getOptions(true)) { $existingItem = $item; } break; } } if ($existingItem) { $item = $existingItem; if ($product->isDownloadable()) { return new JSONResponse(false, 'failure', $this->translate('_downloadable_item_already_exists_in_this_order')); } else { $item->count->set($item->count->get() + 1); } } else { $currency = $shipment->getCurrency(); $item = OrderedItem::getNewInstance($order, $product); $item->count->set(1); $item->price->set($currency->round($item->reduceBaseTaxes($product->getPrice($currency->getID())))); $order->addItem($item); $shipment->addItem($item); $shipment->save(); } $resp = $this->save($item, $shipment, $existingItem ? true : false); if (array_key_exists('errors', $resp)) { $saveResponse['errors'] = array_merge($saveResponse['errors'], $resp['errors']); } else { if (array_key_exists('item', $resp)) { $saveResponse['items'][] = $resp['item']; } } } // for each product if (count($saveResponse['errors']) == 0) { unset($saveResponse['errors']); } if (isset($saveResponse['errors'])) { $response = new JSONResponse(array('errors' => $validator->getErrorList()), 'failure', $this->translate('_unable_to_update_items_quantity')); } else { $response = new JSONResponse($saveResponse, 'success', $this->translate('_item_has_been_successfuly_saved')); } $composite->addResponse('data', $response, $this, 'create'); $ids = array(); foreach ($saveResponse['items'] as $item) { $ids[] = $item['ID']; } $composite->addAction('html', 'backend.orderedItem', 'items'); $this->request->set('item_ids', implode(',', $ids)); $history->saveLog(); return $composite; }
/** * Import or update an ordered product */ protected function set_OrderedItem_sku($instance, $value, $record, CsvImportProfile $profile) { if (!$value) { return; } $product = Product::getInstanceBySKU($value); if (!$product) { return; } $items = $instance->getItemsByProduct($product); // create initial shipment if (!$instance->getShipments()->size()) { $shipment = Shipment::getNewInstance($instance); $shipment->save(); } // any particular shipment? $shipment = $item = null; if ($profile->isColumnSet('OrderedItem.shipment')) { // internal indexes are 0-based, but the import references are 1-based $shipmentNo = $this->getColumnValue($record, $profile, 'OrderedItem.shipment') - 1; if (is_numeric($this->getColumnValue($record, $profile, 'OrderedItem.shipment'))) { foreach ($instance->getShipments() as $key => $shipment) { if ($key == $shipmentNo) { break; } $shipment = null; } // create a new shipment if (!$shipment) { $shipment = Shipment::getNewInstance($instance); $shipment->save(); } foreach ($items as $item) { if ($item->shipment->get() == $shipment) { break; } unset($item); } } } if (!$item) { $item = array_shift($items); } if (!$item) { $count = $this->getColumnValue($record, $profile, 'OrderedItem.count'); $item = OrderedItem::getNewInstance($instance, $product, max(1, $count)); $instance->addItem($item); } if ($profile->isColumnSet('OrderedItem.count')) { $count = $this->getColumnValue($record, $profile, 'OrderedItem.count'); $item->count->set(max(1, $count)); } if ($profile->isColumnSet('OrderedItem.price')) { $item->price->set($this->getColumnValue($record, $profile, 'OrderedItem.price')); } if (!$shipment) { $shipment = $instance->getShipments()->get(0); } $item->shipment->set($shipment); $item->save(); $instance->finalize(array('customPrice' => true, 'allowRefinalize' => true)); }