Payment Status
OroPaymentBundle introduces the payment status represented by the \Oro\Bundle\PaymentBundle\Entity\PaymentStatus entity. The payment status indicates whether the related entity (e.g., an order or an invoice) is paid, partially paid, or unpaid. The payment status is calculated based on the payment transactions associated with the related entity.
The main entry point for working with the payment status is the \Oro\Bundle\PaymentBundle\Manager\PaymentStatusManager class. It provides methods to get, set, and update the payment status of an entity. The manager delegates the actual calculation of the payment status to the \Oro\Bundle\PaymentBundle\PaymentStatus\Calculator\PaymentStatusCalculator class.
The manager allows to set an arbitrary payment status using the setPaymentStatus method. This can be useful in cases where the payment status needs to be set manually, for example, when integrating with a third-party payment gateway that does not provide detailed payment transaction information. You can also set the payment status forcefully using the corresponding argument of the setPaymentStatus method. A payment status set forcefully will not be overridden during the automatic payment status calculation.
When the payment status is changed, the \Oro\Bundle\PaymentBundle\Event\PaymentStatusUpdatedEvent event is dispatched. You can create an event listener for this event to perform additional actions when the payment status is updated.
The following payment statuses are listed in the \Oro\Bundle\PaymentBundle\PaymentStatus\PaymentStatuses and available out-of-the-box:
Paid in Full: The related entity is fully paid.
Partially Paid: The related entity is partially paid.
Invoiced: The related entity is invoiced but not yet paid.
Authorized: The payment is authorized but not yet captured.
Authorized Partially: The payment is authorized partially.
Declined: The payment was declined.
Pending: The payment is pending.
Canceled: The payment was canceled.
Canceled Partially: The payment was partially canceled.
Refunded: The payment was refunded.
Refunded Partially: The payment was partially refunded.
In order to get all available payment statuses, you can use the \Oro\Bundle\PaymentBundle\Provider\AvailablePaymentStatusesProvider - it returns an array of payment statuses for the specified entity class. The result always includes the payment statuses available out-of-the-box and custom payment statuses available for the current user.
Payment Status Calculation
PaymentStatusCalculator is a composite class that delegates the calculation of the payment status to a set of services implementing the \Oro\Bundle\PaymentBundle\PaymentStatus\Calculator\PaymentStatusCalculatorInterface interface. Each provider is responsible for determining if it is applicable to the current context and for providing the corresponding payment status. Each calculator class gets the entity and calculation context - \Oro\Bundle\PaymentBundle\PaymentStatus\Context\PaymentStatusCalculationContext. Out-of-the-box, the context contains the following data:
total - the total amount of the related entity, represented by the
\Oro\Bundle\PricingBundle\SubtotalProcessor\Model\Subtotal. Added by the\Oro\Bundle\PaymentBundle\EventListener\PaymentStatusCalculationContext\SetTotalForPaymentStatusCalculationContextListenerlistener;paymentTransactions - an array of payment transactions associated with the related entity, represented by the
\Oro\Bundle\PaymentBundle\Entity\PaymentTransactionentity. Added by the\Oro\Bundle\PaymentBundle\EventListener\PaymentStatusCalculationContext\SetPaymentTransactionsForPaymentStatusCalculationContextListener.
You can add more data to the payment status calculation context by creating an event listener for the \Oro\Bundle\PaymentBundle\Event\PaymentStatusCalculationContextCollectEvent event.
Payment Status Webhook Notifications
OroPaymentBundle provides \Oro\Bundle\PaymentBundle\Webhook\PaymentStatusWebhookNotifier — a
reusable service for dispatching webhook notifications when a payment transaction completes.
It is designed to be called from event listeners that handle the
\Oro\Bundle\PaymentBundle\Event\TransactionCompleteEvent event
(oro_payment.event.transaction_complete).
When invoked, the notifier assembles a payload in a JSON:API-like structure containing the entity
type and ID, the new payment status code and its human-readable label, the transaction amount and
type, the net amount paid, the remaining amount due, and the currency. It then dispatches two
independent notifications: one to the provided base topic (e.g.,
entity.payment_status_updated) and one to the entity-specific derived topic formed by
appending the entity primary key (e.g., entity.payment_status_updated.42). Both notifications
carry the identical payload.
Payload structure:
{
"topic": "<topic>",
"timestamp": 1741267200,
"messageId": "550e8400-e29b-41d4-a716-446655440000",
"eventData": {
"data": {
"type": "<entity-api-type>",
"id": "<entity-id>",
"attributes": {
"paymentStatus": "<status-code>",
"paymentStatusLabel": "<status-label>",
"transactionAmount": "0.00",
"transactionType": "<action>",
"amountPaid": 0.00,
"amountDue": 0.00,
"currency": "<ISO-4217-code>"
}
}
}
}
Payload attributes:
paymentStatus— the new payment status code (e.g.,paid,partially_paid).paymentStatusLabel— the human-readable label for the payment status.transactionAmount— the amount of the completed transaction.transactionType— the action of the completed transaction (e.g.,capture,purchase,refund).amountPaid— the net amount received: the sum of all successfulCAPTURE,CHARGE, andPURCHASEtransactions minus the sum of all successfulREFUNDtransactions, rounded to the currency precision and clamped to zero.amountDue— the entity total minusamountPaid, clamped to zero.currency— the ISO 4217 currency code.
To send a payment status webhook notification from a custom event listener, inject the
oro_payment.webhook.payment_status_notifier service and call its notify() method with the
registered topic name, the completed PaymentTransaction, and the entity total amount:
use Doctrine\Persistence\ManagerRegistry;
use Oro\Bundle\PaymentBundle\Event\TransactionCompleteEvent;
use Oro\Bundle\PaymentBundle\Webhook\PaymentStatusWebhookNotifier;
class MyPaymentStatusWebhookListener
{
public function __construct(
private readonly PaymentStatusWebhookNotifier $paymentStatusWebhookNotifier,
private readonly ManagerRegistry $registry
) {
}
public function onTransactionComplete(TransactionCompleteEvent $event): void
{
$transaction = $event->getTransaction();
$entity = $this->registry
->getRepository($transaction->getEntityClass())
->find($transaction->getEntityIdentifier());
// ... verify entity type, check feature flags, etc.
$this->paymentStatusWebhookNotifier->notify(
'my_entity.payment_status_updated',
$transaction,
(float) $entity->getTotalAmount()
);
}
}
See also
See Webhooks for information on configuring webhook endpoints and the entity-specific topic subscription pattern.