Ordem múltipla Magento em um checkout ou divisão de pedidos

10

Os produtos da loja são fornecidos por diferentes fornecedores. É necessário criar vários pedidos para cada fornecedor com base em seus produtos no carrinho durante um checkout. Existe alguma extensão para realizar essa tarefa ou devo começar a desenvolver o módulo de checkout personalizado. E os pontos importantes para criar essa visão de extensão de desenvolvedores experientes do Magento? Você pode me explicar uma arquitetura breve do fluxo de checkout amigável ao Magento (o mais possível quanto ao nível do código)? Muito obrigado!

mageUz
fonte
Dê uma olhada no Multishipping que o magento oferece fora da caixa. E existe dropship, mas não tenho idéia se é bom ou o que é capaz de fazer. unirgy.com/products/udropship
Fabian Blechschmidt
@mageUz, você trabalhou abaixo da resposta ?. não funcionou para mim .. Pode postar seu código?
precisa
@ ManojKumar, sim, eu já implementei a divisão de pedidos usando a lógica de checkout de vários endereços, tenho certeza de que a lógica fornecida abaixo também funciona perfeitamente.
mageUz
@mageUz, quando uso este código Carrinho está mostrando vazio .. Todas as sugestões ..
Manoj Kumar
Oi, isso pode ser feito usando o módulo de carrinho de compras dividido market.webkul.com/Magento-Marketplace-Split-Cart.html . Graças
webkul

Respostas:

9

É possível facilmente com a reescrita do checkout/type_onepagemodelo.
Nessa classe, substitua o saveOrder()método da seguinte maneira:

public function saveOrder()
{
    $quote = $this->getQuote();

    // First build an array with the items split by vendor
    $sortedItems = array();
    foreach ($quote->getAllItems() as $item) {
        $vendor = $item->getProduct()->getVendor(); // <- whatever you need
        if (! isset($sortedItems[$vendor])) {
            $sortedItems[$vendor] = $item;
        }
    }
    foreach ($sortedItems as $vendor => $items) {
        // Empty quote
        foreach ($quote->getAllItems() as $item) {
            $quote->getItemsCollection()->removeItemByKey($item->getId());
        }
        foreach ($items as $item) {
            $quote->addItem($item);
        }
        // Update totals for vendor
        $quote->setTotalsCollectedFlag(false)->collectTotals();

        // Delegate to parent method to place an order for each vendor
        parent::saveOrder();
    }
    return $this;
}

Mas esteja ciente de que no Magento um pagamento está associado a uma fatura e cada fatura está associada a um pedido.

Consequentemente, isso significa que, assim que você tiver vários pedidos, você também dividirá os pagamentos . Portanto, isso só é possível se o método de pagamento não exigir interação do usuário durante o pagamento.

UPDATE : A resposta original à parent::save()qual foi delegado parent:saveOrder(). É corrigido no código de exemplo agora.

Vinai
fonte
Gostaria que você pudesse dar uma olhada na minha pergunta semelhante! magento.stackexchange.com/questions/6974/...
CaitlinHavener
você foi capaz de dividir o pedido usando o código acima, como eu estou tentando fazer o mesmo, mas não sem um pouco de sorte
Deepak Mallah
1
Roy, é claro que você precisa estender a classe original para que haja um pai, mas isso é PHP simples, não tem nada a ver com Magento. O método saveOrderainda está presente e ativo no Magento CE 1.9, como sempre foi.
Vinai
3
Eu tive um problema com esse trecho, pois o pedido 2 tem o total e o subtotal iguais a todo o pedido. Após a depuração, descobri que, mesmo removendo e re-adicionando os itens, ele usaria apenas itens em cache de endereço após coletar Total do endereço ... Para resolver isso, basta limpar para cada endereço o cache de itens: $ address-> unsetData (' cached_items_all '); $ address-> unsetData ('cached_items_nominal'); $ address-> unsetData ('cached_items_nonnominal');
Diogo Santiago
1
@Vinai $ quote-> addItem ($ item); este código não está funcionando. Depois de adicionar o item, echo $ quote-> getAllItems () com a ajuda do loop foreach. Mas não havia nenhum item. Você pode me ajudar nisso, por favor?
Amit Bera
1

O seguinte é testado na CE ver 1.9.0.x

/**
 * Overwrite core
 */
class Vendor_Module_Model_Checkout_Type_Onepage extends Mage_Checkout_Model_Type_Onepage
{
    protected $_oriAddresses = array();

    /**
     * Prepare order from quote_items  
     *
     * @param   array of Mage_Sales_Model_Quote_Item 
     * @return  Mage_Sales_Model_Order
     * @throws  Mage_Checkout_Exception
     */
    protected function _prepareOrder2($quoteItems)
    {
        $quote = $this->getQuote();
        $quote->unsReservedOrderId();
        $quote->reserveOrderId();

        // new instance of quote address
        $quote->setIsMultiShipping(true); // required for new instance of Mage_Sales_Model_Quote_Address
        $address = Mage::getModel('sales/quote_address');
        $weight = 0;
        $addressType = 'billing';
        foreach ($quoteItems as $quoteItem) {
            $address->addItem($quoteItem, $quoteItem->getQty());
            $weight += $quoteItem->getWeight();
            if (!$quoteItem->getIsVirtual()) {
                $addressType = 'shipping';
            }
        }
        // get original shipping address that contains multiple quote_items
        if (!isset($this->_oriAddresses[$addressType])) {
            $this->_oriAddresses[$addressType] = Mage::getResourceModel('sales/quote_address_collection')
                ->setQuoteFilter($quote->getId())
                ->addFieldToFilter('address_type', $addressType)
                ->getFirstItem();
        }
        Mage::helper('core')->copyFieldset('sales_convert_quote_address', 'to_customer_address', $this->_oriAddresses[$addressType], $address);
        Mage::helper('core')->copyFieldset('sales_convert_quote_address', 'to_order', $this->_oriAddresses[$addressType], $address);
        $address->setQuote($quote)
            ->setWeight($weight)
            ->setSubtotal(0)
            ->setBaseSubtotal(0)
            ->setGrandTotal(0)
            ->setBaseGrandTotal(0)
            ->setCollectShippingRates(true)
            ->collectTotals()
            ->collectShippingRates()        
            ;

        $convertQuote = Mage::getSingleton('sales/convert_quote');
        $order = $convertQuote->addressToOrder($address);
        $order->setBillingAddress(
            $convertQuote->addressToOrderAddress($quote->getBillingAddress())
        );

        if ($address->getAddressType() == 'billing') {
            $order->setIsVirtual(1);
        } else {
            $order->setShippingAddress($convertQuote->addressToOrderAddress($address));
        }

        $order->setPayment($convertQuote->paymentToOrderPayment($quote->getPayment()));
        if (Mage::app()->getStore()->roundPrice($address->getGrandTotal()) == 0) {
            $order->getPayment()->setMethod('free');
        }

        foreach ($quoteItems as $quoteItem) {
            $orderItem = $convertQuote->itemToOrderItem($quoteItem);  // use quote_item to transfer is_qty_decimal
            if ($quoteItem->getParentItem()) {
                $orderItem->setParentItem($order->getItemByQuoteItemId($quoteItem->getParentItem()->getId()));
            }
            $order->addItem($orderItem);
        }

        return $order;
    }

    /**
     * Overwrite core function
     */
    public function saveOrder()
    {
        $quote = $this->getQuote();
        if ($quote->getItemsCount() > 1) {
            $items = $quote->getAllVisibleItems();
            $group = array();
            $split = array();
            foreach ($items as $item) {
                if (Mage::helper('vendor')->checkSku($item->getSku())) {
                    $split[] = array($item); // one item per order
                } else {
                    $group[] = $item; // all other items in one order
                }
            }
            if (count($split)) {
                if (count($group)) {
                    $split[] = $group;
                }
                return $this->_splitQuote($split);
            }
        }
        return parent::saveOrder();
    }

    /**
     * Split quote to multiple orders
     * 
     * @param array of Mage_Sales_Model_Quote_Item
     * @return Mage_Checkout_Model_Type_Onepage
     */
    protected function _splitQuote($split)
    {
        $this->validate();
        $isNewCustomer = false;
        switch ($this->getCheckoutMethod()) {
            case self::METHOD_GUEST:
                $this->_prepareGuestQuote();
                break;
            case self::METHOD_REGISTER:
                $this->_prepareNewCustomerQuote();
                $isNewCustomer = true;
                break;
            default:
                $this->_prepareCustomerQuote();
                break;
        }
        if ($isNewCustomer) {
            try {
                $this->_involveNewCustomer();
            } catch (Exception $e) {
                Mage::logException($e);
            }
        }

        $quote = $this->getQuote()->save();
        $orderIds = array();
        Mage::getSingleton('core/session')->unsOrderIds();
        $this->_checkoutSession->clearHelperData();

        /**
         * a flag to set that there will be redirect to third party after confirmation
         * eg: paypal standard ipn
         */
        $redirectUrl = $quote->getPayment()->getOrderPlaceRedirectUrl();

        foreach ($split as $quoteItems) {
            $order = $this->_prepareOrder2($quoteItems);
            $order->place();
            $order->save();
            Mage::dispatchEvent('checkout_type_onepage_save_order_after',
                array('order'=>$order, 'quote'=>$quote));
            /**
             * we only want to send to customer about new order when there is no redirect to third party
             */
            if (!$redirectUrl && $order->getCanSendNewEmailFlag()) {
                $order->sendNewOrderEmail();
            }
            $orderIds[$order->getId()] = $order->getIncrementId();
        }

        Mage::getSingleton('core/session')->setOrderIds($orderIds);

        // add order information to the session
        $this->_checkoutSession
            ->setLastQuoteId($quote->getId())
            ->setLastSuccessQuoteId($quote->getId())
            ->setLastOrderId($order->getId())
            ->setRedirectUrl($redirectUrl)
            ->setLastRealOrderId($order->getIncrementId());

        // as well a billing agreement can be created
        $agreement = $order->getPayment()->getBillingAgreement();
        if ($agreement) {
            $this->_checkoutSession->setLastBillingAgreementId($agreement->getId());
        }

        // add recurring profiles information to the session
        $service = Mage::getModel('sales/service_quote', $quote);
        $profiles = $service->getRecurringPaymentProfiles();
        if ($profiles) {
            $ids = array();
            foreach ($profiles as $profile) {
                $ids[] = $profile->getId();
            }
            $this->_checkoutSession->setLastRecurringProfileIds($ids);
            // TODO: send recurring profile emails
        }

        Mage::dispatchEvent(
            'checkout_submit_all_after',
            array('order' => $order, 'quote' => $quote, 'recurring_profiles' => $profiles)
        );

        return $this;
    }
}

IMPORTANTE Você precisa personalizar seus métodos de pagamento para recuperar o total geral da cotação.

kiatng
fonte
Está funcionando. Obrigado. Como agrupar cotação de carrinho por fornecedor? outro, em seguida, "// um item por pedido" ..
Syed Ibrahim
1
$group[] = $item; // all other items in one orderpode conter vários itens por pedido, você pode modificar facilmente para que cada fornecedor tenha o seu $group.
kiatng
Atualizado e está funcionando. Mas o pagamento é capturado apenas para o último pedido (se dividirmos o pedido múltiplo). Como precisamos atualizar isso? Preciso coletar o total do pagamento combinado.
Syed Ibrahim
O valor total está no objeto de cotação, com o qual você pode carregá-lo $quote->Mage::getModel('sales/quote')->load($lastOrder->getQuoteId()). Então há muitas totais você pode recuperar a partir $quote, um dos quais é$quote->getGrandTotal()
kiatng