Pedido múltiple de Magento en un proceso de pago o división de pedidos

10

Los productos de la tienda se suministran de diferentes proveedores. Se requiere crear múltiples pedidos para cada proveedor en función de sus productos en el carrito durante un pago. ¿Hay alguna extensión para lograr esta tarea o debería comenzar a desarrollar un módulo de pago personalizado? ¿Qué pasa con los puntos calientes para crear una visión de extensión de desarrolladores experimentados de Magento? ¿Me puede explicar breve arquitectura de flujo de pago amigable con Magento (tan posible como nivel de código)? Muchas gracias mas!

mageUz
fuente
Eche un vistazo al Multishipping que ofrece magento de fábrica. Y hay dropship pero no tengo idea si es bueno o qué es capaz de hacer. unirgy.com/products/udropship
Fabian Blechschmidt
@mageUz, ¿has trabajado debajo de la respuesta? no me funcionó .. ¿Puedes publicar tu código?
Manoj Kumar
@ManojKumar, sí, ya he implementado la división de pedidos usando la lógica de pago de múltiples direcciones, estoy seguro de que la lógica que se muestra a continuación también funciona perfectamente.
mageUz
@mageUz, cuando use este código El carrito de compras está vacío mostrando ... Cualquier sugerencia ...
Manoj Kumar
Hola, eso se puede hacer con el módulo de carro dividido del mercado store.webkul.com/Magento-Marketplace-Split-Cart.html . Gracias
webkul

Respuestas:

9

Es factible con bastante facilidad con una reescritura del checkout/type_onepagemodelo.
En esa clase, anule el saveOrder()método de la siguiente manera:

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;
}

Pero tenga en cuenta que en Magento un pago está asociado con una factura, y cada factura está asociada con un pedido.

En consecuencia, esto significa que tan pronto como tenga varios pedidos, también habrá dividido los pagos . Por lo tanto, esto solo es factible si el método de pago no requiere la interacción del usuario durante el pago.

ACTUALIZACIÓN : La respuesta original delegada a la parent::save()que tenía que ser parent:saveOrder(). Está arreglado en el código de ejemplo ahora.

Vinaí
fuente
¡Le agradecería si pudiera echar un vistazo a mi pregunta similar! magento.stackexchange.com/questions/6974/…
CaitlinHavener
¿Pudiste dividir el orden usando el código anterior, ya que estoy tratando de hacer lo mismo pero no sin suerte?
Deepak Mallah
1
Roy, por supuesto, tienes que extender la clase original para que haya un padre, pero eso es PHP simple, no tiene nada que ver con Magento. El método saveOrdertodavía está presente y activo en Magento CE 1.9 como siempre lo ha estado.
Vinai
3
Tuve un problema con este fragmento ya que el orden 2 tiene el grandtotal y el subtotal igual al orden completo. Después de la depuración descubrí que incluso eliminando y volviendo a agregar los elementos, solo usaría los elementos almacenados en la dirección en caché después de recopilar Total form the address ... Para resolverlo, simplemente borre para cada dirección el caché de elementos: $ 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 no funciona. Después de agregar el elemento, hago eco de $ quote-> getAllItems () con ayuda del bucle foreach. Pero no había ningún artículo. ¿Me pueden ayudar en esto por favor?
Amit Bera
1

Lo siguiente se prueba en 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 Debe personalizar sus métodos de pago para recuperar el total general de la cotización.

kiatng
fuente
Está funcionando. Gracias. ¿Cómo agrupar el presupuesto del carrito por proveedor? aparte de "// un artículo por pedido" ..
Syed Ibrahim
1
$group[] = $item; // all other items in one orderpuede contener varios artículos por pedido, puede modificarlos fácilmente para que cada proveedor tenga los suyos $group.
kiatng
Actualizado y está funcionando. Pero el pago se captura solo para el último pedido (si dividimos varios pedidos). ¿Cómo necesitamos actualizar esto? Necesito cobrar el total del pago combinado.
Syed Ibrahim
El importe total está en el objeto de presupuesto, puede cargarlo $quote->Mage::getModel('sales/quote')->load($lastOrder->getQuoteId()). Entonces hay muchas totales que se pueden recuperar a partir $quote, uno de los cuales es$quote->getGrandTotal()
kiatng