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_braintreeif using Braintree,paypal_expressfor standard Express Checkout). You can find valid codes in thepayment_methoddatabase 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
_objectManagerdirectly — inject theUpdateOrderPaymentToPayPalservice via your class constructor. - Transaction Types: Match the
TxnTypeto your actual PayPal transaction (captured, authorized, refunded, etc.).
内容的提问来源于stack exchange,提问作者Sreejith Gopinath
相关产品推荐
相关产品推荐

