1

I am creating a custom module to create orders programatically with paypal_billing_agreement as payment method. Below is the order creation code I use.

<?php

namespace Vendor\Module\Model\Subscription\Order;

class Create
{
    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Catalog\Model\ProductFactory $productFactory,
        \Magento\Quote\Model\QuoteManagement $quoteManagement,
        \Magento\Customer\Model\CustomerFactory $customerFactory,
        \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository,
        \Magento\Sales\Model\Service\OrderService $orderService,
        \Magento\Quote\Api\CartRepositoryInterface $cartRepositoryInterface,
        \Magento\Quote\Api\CartManagementInterface $cartManagementInterface,
        \Magento\Quote\Model\Quote\Address\Rate $shippingRate
    ) {
        $this->_storeManager = $storeManager;
        $this->_productFactory = $productFactory;
        $this->quoteManagement = $quoteManagement;
        $this->customerFactory = $customerFactory;
        $this->customerRepository = $customerRepository;
        $this->orderService = $orderService;
        $this->cartRepositoryInterface = $cartRepositoryInterface;
        $this->cartManagementInterface = $cartManagementInterface;
        $this->shippingRate = $shippingRate;
    }
    /**
     * Create Order On Your Store
     *
     * @param array $orderData
     * @return int $orderId
     *
     */
    public function createOrder($orderData) {

        //init the store id and website id @todo pass from array
        $store = $this->_storeManager->getStore();
        $websiteId = $this->_storeManager->getStore()->getWebsiteId();
        //init the customer
        $customer=$this->customerFactory->create();
        $customer->setWebsiteId($websiteId);
        $customer->loadByEmail($orderData['email']);// load customet by email address
        //check the customer
        if(!$customer->getEntityId()){
            //If not avilable then create this customer
            $customer->setWebsiteId($websiteId)
                ->setStore($store)
                ->setFirstname($orderData['shipping_address']['firstname'])
                ->setLastname($orderData['shipping_address']['lastname'])
                ->setEmail($orderData['email'])
                ->setPassword($orderData['email']);
            $customer->save();
        }
        //init the quote
        $cart_id = $this->cartManagementInterface->createEmptyCart();
        $cart = $this->cartRepositoryInterface->get($cart_id);
        $cart->setStore($store);
        // if you have already buyer id then you can load customer directly
        $customer= $this->customerRepository->getById($customer->getEntityId());
        $cart->setCurrency();
        $cart->assignCustomer($customer); //Assign quote to customer
        //add items in quote
        foreach($orderData['items'] as $item){
            $product = $this->_productFactory->create()->load($item['product_id']);
            $cart->addProduct(
                $product,
                intval($item['qty'])
            );
        }
        //Set Address to quote 
        $cart->getBillingAddress()->addData($orderData['shipping_address']);
        $cart->getShippingAddress()->addData($orderData['shipping_address']);
        // Collect Rates and Set Shipping & Payment Method
        $this->shippingRate
            ->setCode('freeshipping_freeshipping')
            ->getPrice(1);
        $shippingAddress = $cart->getShippingAddress();
        //@todo set in order data
        $shippingAddress->setCollectShippingRates(true)
            ->collectShippingRates()
            ->setShippingMethod('flatrate_flatrate'); //shipping method
        $cart->getShippingAddress()->addShippingRate($this->shippingRate);
        $cart->setPaymentMethod('paypal_billing_agreement'); //payment method
        //@todo insert a variable to affect the invetory
        $cart->setInventoryProcessed(false);
        // Set sales order payment
        $cart->getPayment()->importData(['method' => 'payapal_billing_agreement,'reference_id' => 'B-RTRHFHs8428355236']);
        // Collect total and saeve
        $cart->collectTotals();
        // Submit the quote and create the order
        $cart->save();
        $cart = $this->cartRepositoryInterface->get($cart->getId());
        $order_id = $this->cartManagementInterface->placeOrder($cart->getId());
        return $order_id;
    }
}

When I change the payment method to "free" it works. paypal billing agreement payment method requires a additional data as I inspect the actual billing agreement flow from checkout.

{method: "paypal_billing_agreement", additional_data: {…}}
additional_data:{ba_agreement_id: "5"}
method:"paypal_billing_agreement"

I have even tride to add the same with import data for getpayment method but same issue persists. The request post to callDoReferenceTransaction() has all required parameters set correctly except the REFERENCEID is set as NULL.

Note: using the default NVP api of PayPal that is provided for magento 2.1.

Exception thrown is:

1 exception(s):
Exception #0 (Magento\Framework\Exception\LocalizedException): PayPal gateway has rejected request. ReferenceID : Mandatory parameter missing (#81253: Missing Parameter)

.

What am I missing.?

Thanks in advance for any help.

Naresh Kumar
  • 1,706
  • 1
  • 14
  • 26

1 Answers1

2

So I have found the solution,

Pre-Requisites, first I had to enable the Billing agreement order creation from backend.

To do so i have made changes in the Observer that by default set "is_allowed" to false to true in module-paypal.

Then made the following change in code to create order using reference transaction,

$cart->setPaymentMethod('paypal_billing_agreement'); //payment method
$cart->setInventoryProcessed(false);
// Set sales order payment

$cart->getPayment()->setAdditionalInformation("ba_agreement_id","1");//To point the correct billing agreement in billing agreement table.

$cart->getPayment()->importData(['method' => 'paypal_billing_agreement,'reference_id' => 'B-RTRHFHs8428355236']);
// Collect total and saeve
$cart->collectTotals();
// Submit the quote and create the order
$cart->save();

And ofcourse finished things with wrapping in try catch to handle exceptions

Naresh Kumar
  • 1,706
  • 1
  • 14
  • 26