You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Magento 2.1:程序化更新订单支付方式及PayPal交易详情问询

Programmatically Update Order Payment Method to PayPal (Magento 2.1)

Alright, let's walk through how to switch an existing Magento 2.1 order's payment method from checkmo to PayPal, and populate it with the completed transaction details you've already fetched via the PayPal API. This approach follows Magento's best practices using dependency injection and service classes.

Prerequisites

  • You have the target order's ID
  • You have full transaction details from PayPal (transaction ID, status, amount, currency, etc.)
  • The order is in a modifiable state (e.g., pending_payment — avoid updating orders that are already shipped/invoiced unless you adjust for that)

Step 1: Create a Service Class for Payment Updates

First, build a reusable service class to handle the payment switch. This keeps your code clean and aligned with Magento's architecture.

Inject Required Dependencies

<?php
namespace Your\CustomModule\Service;

use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\Order\PaymentFactory;
use Magento\Sales\Model\Order\Payment\TransactionFactory;
use Magento\Sales\Model\ResourceModel\Order\Payment\Transaction as TransactionResource;
use Magento\Framework\Exception\LocalizedException;
use Magento\Sales\Model\Order;

class UpdateOrderPaymentToPayPal
{
    protected $orderRepository;
    protected $paymentFactory;
    protected $transactionFactory;
    protected $transactionResource;

    public function __construct(
        OrderRepositoryInterface $orderRepository,
        PaymentFactory $paymentFactory,
        TransactionFactory $transactionFactory,
        TransactionResource $transactionResource
    ) {
        $this->orderRepository = $orderRepository;
        $this->paymentFactory = $paymentFactory;
        $this->transactionFactory = $transactionFactory;
        $this->transactionResource = $transactionResource;
    }

Step 2: Add the Core Update Logic

Add this method to the service class to handle the payment method switch and transaction data insertion:

public function execute(int $orderId, array $payPalTransactionData): bool
    {
        try {
            // Load the existing order
            /** @var Order $order */
            $order = $this->orderRepository->get($orderId);

            // Verify the order can be modified
            if (!$order->canEdit()) {
                throw new LocalizedException(__('This order cannot be edited at this time.'));
            }

            // Remove the existing checkmo payment record
            $existingPayment = $order->getPayment();
            if ($existingPayment) {
                $existingPayment->delete();
            }

            // Create a new PayPal payment instance
            $payment = $this->paymentFactory->create();
            $payment->setOrder($order);
            // Use your actual PayPal payment method code (check `payment_method` table for correct value)
            $payment->setMethod('paypal_express'); 
            $payment->setAmountOrdered($order->getGrandTotal());
            $payment->setBaseAmountOrdered($order->getBaseGrandTotal());
            $payment->setAmountPaid($order->getGrandTotal());
            $payment->setBaseAmountPaid($order->getBaseGrandTotal());

            // Attach PayPal transaction details to the payment
            $payment->setAdditionalInformation([
                'transaction_id' => $payPalTransactionData['transaction_id'],
                'paypal_status' => $payPalTransactionData['status'],
                'amount' => $payPalTransactionData['amount'],
                'currency' => $payPalTransactionData['currency'],
                // Add any other relevant fields from your PayPal API response
            ]);

            // Save the payment to the order
            $order->setPayment($payment);
            $this->orderRepository->save($order);

            // Create a formal transaction record in Magento
            $transaction = $this->transactionFactory->create();
            $transaction->setPaymentId($payment->getId());
            $transaction->setOrderId($order->getId());
            $transaction->setTxnId($payPalTransactionData['transaction_id']);
            // Use TYPE_AUTH if this was an authorization, TYPE_REFUND if it's a refund, etc.
            $transaction->setTxnType(\Magento\Sales\Model\Order\Payment\Transaction::TYPE_CAPTURE); 
            $transaction->setIsClosed(true);
            $transaction->setAdditionalInformation(
                \Magento\Sales\Model\Order\Payment\Transaction::RAW_DETAILS,
                $payPalTransactionData
            );

            $this->transactionResource->save($transaction);

            // Update order state to reflect completed payment
            $order->setState(Order::STATE_PROCESSING)
                  ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_PROCESSING));
            $this->orderRepository->save($order);

            return true;
        } catch (LocalizedException $e) {
            // Log the error (use Magento's logger instead of echo in production)
            error_log("Payment update failed: " . $e->getMessage());
            throw new LocalizedException(__('Failed to update payment method: %1', $e->getMessage()));
        }
    }
}

Step 3: Use the Service Class

Call this service from wherever you need (controller, cron job, etc.). For example:

<?php
// Example usage in a controller (inject the service via constructor in production)
use Your\CustomModule\Service\UpdateOrderPaymentToPayPal;

// Your PayPal transaction data from the API response
$payPalTransaction = [
    'transaction_id' => 'PAY-123ABC456DEF789',
    'status' => 'COMPLETED',
    'amount' => '49.99',
    'currency' => 'USD',
    'payer_email' => 'customer@example.com'
];

$orderId = 123; // Replace with your order ID

try {
    $paymentUpdater = $this->_objectManager->create(UpdateOrderPaymentToPayPal::class);
    $paymentUpdater->execute($orderId, $payPalTransaction);
    echo "Payment method updated to PayPal successfully!";
} catch (\Exception $e) {
    echo "Error: " . $e->getMessage();
}

Key Notes to Avoid Issues

  • Payment Method Code: Double-check the correct code for your PayPal integration (e.g., paypal_braintree if using Braintree, paypal_express for standard Express Checkout). You can find valid codes in the payment_method database table.
  • Order State: If the order is already invoiced or shipped, you may need to cancel existing invoices first or adjust the logic to handle partial payments.
  • Dependency Injection: In production code, avoid using _objectManager directly — inject the UpdateOrderPaymentToPayPal service via your class constructor.
  • Transaction Types: Match the TxnType to your actual PayPal transaction (captured, authorized, refunded, etc.).

内容的提问来源于stack exchange,提问作者Sreejith Gopinath

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:18:17