3

I'm going to create an order programmatically without a payment. But it requires to set a valid payment method when I run the following code. Is there any way to skip it?

    $quote = $this->_quoteFactory->create();
    $quote->setStore($store);
    $quote->setCurrency($store->getCurrentCurrency()->getDataModel());
    $quote->assignCustomer($customer->getDataModel());
    $quote->addProduct($product);
    $quote->setPaymentMethod('checkmo'); 
    $quote->save();
    $order = $this->_quoteManagement->submit($quote);
2

As far as I know, in Magento 2.0.2 - 2.1 version, we cannot create an order without any payment methods.

Magento sets payment for order: vendor/magento/module-quote/Model/QuoteManagement.php

$order->setPayment($this->quotePaymentToOrderPayment->convert($quote->getPayment()));

Convert payment from quote object:

vendor/magento/module-quote/Model/Quote/Payment/ToOrderPayment.php

 $orderPayment->setAdditionalInformation(
            array_merge(
                $object->getAdditionalInformation(),
                [Substitution::INFO_KEY_TITLE => $object->getMethodInstance()->getTitle()]
            )
        );

And then getting method instance:

vendor/magento/module-payment/Model/Info.php

  public function getMethodInstance()
  {
        if (!$this->hasMethodInstance()) {
            if (!$this->getMethod()) {
                throw new \Magento\Framework\Exception\LocalizedException(
                    __('The payment method you requested is not available.')
                );
            }

            try {
                $instance = $this->_paymentData->getMethodInstance($this->getMethod());
            } catch (\UnexpectedValueException $e) {
                $instance = $this->_paymentData->getMethodInstance(Method\Substitution::CODE);
            }

            $instance->setInfoInstance($this);
            $this->setMethodInstance($instance);
        }

        return $this->_getData('method_instance');
  }

In cases, Magento will check the available payment methods. If it doesn't have any payment methods, it will throw exceptions.

A Substitution payment method is assigned if non-existing payments: vendor/magento/module-payment/Model/Method/Substitution.php

  • Thanks @khoa, is there a payment method called "free"? I try it but still no hope – Paul Aug 11 '16 at 13:59
  • 1
    You can use getPaymentMethodList in vendor/magento/module-payment/Helper/Data.php. You can also see some offline payments: vendor/magento/module-offline-payments/Model. For example: Bank Tranfer: \Magento\OfflinePayments\Model\Banktransfer::PAYMENT_METHOD_BANKTRANSFER_CODE – Khoa TruongDinh Aug 11 '16 at 17:02
  • 1
    We have enabled paypal express checkout as the only payment method. But when I set $quote->setPaymentMethod('wps_express'), it returns The requested Payment Method is not available.. Do you know why? – Paul Aug 12 '16 at 2:20
  • 1
    To others who reference this later: the above answers are wrong or else out of date. There is a "free" method (Zero Subtotal Checkout). – Scott Buchanan Mar 31 '17 at 2:09
  • 1
    @ScottSB Yes, you're right! Thanks! However, my answer may not be wrong. My comment was wrong. I have just deleted it. – Khoa TruongDinh Mar 31 '17 at 2:33
1

The other answer by Khoa TruongDinh is correct that Magento does require you to set a payment method, but in most similar cases the goal is simply to create an order without payment details: not specifically without a payment method at all.

In order to avoid specifying payment details, there are two generic built-in payment methods that you can use to fulfill Magento's requirement:

  • Zero Subtotal Payment: 'free'
  • Check/Money Order: 'checkmo'

The Zero Subtotal Payment requires a subtotal of zero (surprise, surprise), while the Check/Money Order method can be used with any subtotal. Both can be renamed to appear as other names through the Magento admin configuration.

To set one of these methods on a quote, inject \Magento\Quote\Model\Quote\PaymentFactory into your class, set it to $this->paymentFactory in your constructor, and then do the following (replacing "[method code]" with either 'free' or 'checkmo' as desired):

$payment = $this->paymentFactory->create();
$payment->setMethod([method code]);
$quote->setPayment($payment);

The issue with the code in the original question was that it attempts to use a non-existent method (setPaymentMethod) to set the payment code directly on the quote. Instead, you must create a Payment object as above.

  • 1
    There is another offline payment: Bank Transfer: vendor/magento/module-offline-payments/Model/Banktransfer.php. – Khoa TruongDinh Mar 31 '17 at 2:31
  • quote.setPaymentMethod(), then what it means, Can you tell me – Jaisa Jun 8 '18 at 7:02
  • @Sri Sorry, I don't understand your question. Can you try rephrasing it? – Scott Buchanan Jun 8 '18 at 13:57
  • How Do I unset the selected payment method using the below code quote.setPaymentMethod(). Please refer this magento.stackexchange.com/questions/229212/… – Jaisa Jun 8 '18 at 14:04
  • I'm still not clear on what you mean. Are you trying to unset it in the front-end Knockout model or in the server-side PHP/database model? The other question you linked (and the one it links to) are about front-end refreshes, but the original question I answered here was about server-side code. – Scott Buchanan Jun 8 '18 at 21:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.