Magento commande multiple en une seule commande ou fractionnement de commande

10

Les produits en magasin sont fournis par différents fournisseurs. Il est nécessaire de créer plusieurs commandes pour chaque fournisseur en fonction de ses produits dans le panier lors d'une seule commande. Existe-t-il une extension pour réaliser cette tâche ou dois-je commencer à développer un module de paiement personnalisé. Qu'en est-il des points chauds pour créer une telle vision d'extension des développeurs expérimentés de Magento? Pouvez-vous m'expliquer une brève architecture de flux de paiement compatible avec Magento (aussi possible que le niveau de code)? Merci beaucoup plus!

mageUz
la source
Jetez un oeil sur le Multishipping que magento propose dès la sortie de la boîte. Et il y a du dropship mais je n'ai aucune idée si c'est bon ou ce qu'il est capable de faire. unirgy.com/products/udropship
Fabian Blechschmidt
@mageUz, avez-vous travaillé ci-dessous pour répondre?. ça n'a pas fonctionné pour moi .. Vous pouvez poster votre code?
Manoj Kumar
@ManojKumar, oui, j'ai déjà implémenté le fractionnement des commandes en utilisant la logique de paiement multi-adresses, je suis sûr que la logique donnée ci-dessous fonctionne également parfaitement.
mageUz
@mageUz, lorsque vous utilisez ce code Le panier est vide et affiche .. Toutes suggestions ..
Manoj Kumar
Bonjour, cela peut être fait en utilisant le module de panier divisé du marché store.webkul.com/Magento-Marketplace-Split-Cart.html . Merci
webkul

Réponses:

9

C'est faisable assez facilement avec une réécriture du checkout/type_onepagemodèle.
Dans cette classe, remplacez la saveOrder()méthode comme suit:

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

Mais sachez que dans Magento, un paiement est associé à une facture, et chaque facture est associée à une commande.

En conséquence, cela signifie que dès que vous avez plusieurs commandes, vous avez également fractionné les paiements . Cela n'est donc possible que si le mode de paiement ne nécessite pas d'interaction de l'utilisateur lors du paiement.

MISE À JOUR : La réponse originale déléguée à parent::save()laquelle devait être parent:saveOrder(). Il est maintenant corrigé dans l'exemple de code.

Vinai
la source
J'apprécierais si vous pouviez jeter un œil à ma question similaire! magento.stackexchange.com/questions/6974/…
CaitlinHavener
avez-vous pu diviser la commande en utilisant le code ci-dessus, car j'essaye de faire la même chose mais pas sans aucune chance
Deepak Mallah
1
Roy, bien sûr, vous devez étendre la classe d'origine pour qu'il y ait un parent, mais c'est du PHP simple, cela n'a rien à voir avec Magento. La méthode saveOrderest toujours présente et active dans Magento CE 1.9 comme elle l'a toujours été.
Vinai
3
J'ai rencontré un problème avec cet extrait de code, car les 2 commandes ont le grand total et le sous-total égal à la totalité de la commande. Après le débogage, j'ai découvert que même en supprimant et en rajoutant les éléments, il suffit d'utiliser les éléments mis en cache d'adresse après avoir collecté Total sous l'adresse ... Pour le résoudre, effacez simplement pour chaque adresse le cache des éléments: $ address-> unsetData (' cached_items_all '); $ address-> unsetData ('cached_items_nominal'); $ address-> unsetData ('cached_items_nonnominal');
Diogo Santiago du
1
@Vinai $ quote-> addItem ($ item); ce code ne fonctionne pas. Après avoir ajouté un élément, je fais écho à $ quote-> getAllItems () à l'aide de la boucle foreach. Mais il n'y avait aucun article. Pouvez-vous m'aider à ce sujet s'il vous plaît?
Amit Bera
1

Ce qui suit est testé dans 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;
    }
}

IMPORTANT Vous devez personnaliser vos méthodes de paiement pour récupérer le total général du devis.

kiatng
la source
Ça fonctionne. Merci. Comment grouper un devis de chariot par fournisseur? autre que "// un article par commande" ..
Syed Ibrahim
1
$group[] = $item; // all other items in one orderpeut contenir plusieurs articles par commande, vous pouvez facilement modifier de telle sorte que chaque fournisseur possède le sien $group.
kiatng
Mis à jour et cela fonctionne. Mais le paiement n'est capturé que pour la dernière commande (si nous fractionnons plusieurs commandes). Comment devons-nous mettre cela à jour? Je dois collecter le total des paiements combinés.
Syed Ibrahim
Le montant total est dans l'objet devis, vous pouvez le charger avec $quote->Mage::getModel('sales/quote')->load($lastOrder->getQuoteId()). Ensuite, vous pouvez récupérer de nombreux totaux $quote, dont l'un est$quote->getGrandTotal()
kiatng