Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add events and logging for payments #797

Open
wants to merge 4 commits into
base: 8.x-2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions modules/log/commerce_log.commerce_log_categories.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ commerce_cart:
commerce_order:
label: Order
entity_type: commerce_order

commerce_payment:
label: Payment
entity_type: commerce_payment
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this read commerce_order?

9 changes: 9 additions & 0 deletions modules/log/commerce_log.commerce_log_templates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,12 @@ order_assigned:
category: commerce_order
label: 'Order assigned'
template: '<p>The order was assigned to {{ user }}.</p>'

payment_log:
category: commerce_payment
label: 'Payment log'
template: '<p>{% if new %} New payment {% else %} Payment {% endif %} {% if remote_id %} {{ remote_id }} {% else %} {{ id }} {% endif %} {% if not previous_amount %} of {{ amount|commerce_price_format }} {% endif %} in state {{ state}} {% if previous_amount %} was changed from {{ previous_amount|commerce_price_format }} to {{ amount|commerce_price_format }} {% endif %}.</p>'
payment_refunded:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured that insert, update, delete and refund are the only things of interest.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like we want more details in the messages. Let's add the current state as part of the log too.

category: commerce_payment
label: 'Payment refunded'
template: '<p>{% if new %} New payment {% else %} Payment {% endif %} {% if remote_id %} {{ remote_id }} {% else %} {{ id }} {% endif %} was refunded {{ refunded_amount|commerce_price_format }} and is now in state {{ state }}.</p>'
12 changes: 12 additions & 0 deletions modules/log/commerce_log.module
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* Provides activity logs for Commerce entities.
*/

use Drupal\commerce_log\PaymentListBuilder;

/**
* Implements hook_preprocess_commerce_order().
*/
Expand All @@ -20,3 +22,13 @@ function commerce_log_preprocess_commerce_order(&$variables) {
'#title' => t('Order activity'),
];
}

/**
* Implements hook_entity_type_alter() for commerce_payment.
*/
function commerce_log_entity_type_alter(array &$entity_types) {
if (isset($entity_types['commerce_payment'])) {
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
$entity_types['commerce_payment']->setListBuilderClass(PaymentListBuilder::class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ display:
entity_type: commerce_log
entity_field: log_id
plugin_id: standard
title: 'Order logs'
title: 'Order activity'
header: { }
footer: { }
empty:
Expand Down
6 changes: 6 additions & 0 deletions modules/log/src/CommerceLogServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Drupal\commerce_log;

use Drupal\commerce_log\EventSubscriber\PaymentEventSubscriber;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Symfony\Component\DependencyInjection\Reference;
Expand Down Expand Up @@ -29,6 +30,11 @@ public function register(ContainerBuilder $container) {
->addTag('event_subscriber')
->addArgument(new Reference('entity_type.manager'));
}
if (isset($modules['commerce_payment'])) {
$container->register('commerce_log.payment_subscriber', PaymentEventSubscriber::class)
->addTag('event_subscriber')
->addArgument(new Reference('entity_type.manager'));
}
}

}
108 changes: 108 additions & 0 deletions modules/log/src/EventSubscriber/PaymentEventSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace Drupal\commerce_log\EventSubscriber;

use Drupal\commerce_payment\Entity\PaymentInterface;
use Drupal\commerce_payment\Event\PaymentEvent;
use Drupal\commerce_payment\Event\PaymentEvents;
use Drupal\commerce_price\Calculator;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class PaymentEventSubscriber implements EventSubscriberInterface {

/**
* The log storage.
*
* @var \Drupal\commerce_log\LogStorageInterface
*/
protected $logStorage;

/**
* Constructs a new PaymentEventSubscriber object.
*
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->logStorage = $entity_type_manager->getStorage('commerce_log');
}

/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
$events = [
PaymentEvents::PAYMENT_PRESAVE => ['onPaymentPresave', -100],
PaymentEvents::PAYMENT_PREDELETE => ['onPaymentPredelete', -100],
];
return $events;
}

/**
* Creates a log before a payment is saved.
*
* @param \Drupal\commerce_payment\Event\PaymentEvent $event
* The payment event.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function onPaymentPresave(PaymentEvent $event) {
$this->logPayment($event->getPayment());
}

/**
* Creates a log when a payment is deleted.
*
* @param \Drupal\commerce_payment\Event\PaymentEvent $event
* The payment event.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function onPaymentPredelete(PaymentEvent $event) {
$event->getPayment()->setState('deleted');
$this->logPayment($event->getPayment());
}

/**
* Creates a log when a payment is changed.
*
* @param \Drupal\commerce_payment\Entity\PaymentInterface $payment
* The payment.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
protected function logPayment(PaymentInterface $payment) {
$refund = $payment->getRefundedAmount();
$isNew = $payment->isNew();
$previousAmount = FALSE;
if (!empty($payment->original) && !$payment->getAmount()->equals($payment->original->getAmount())) {
$previousAmount = $payment->original->getAmount();
}
if ($refund && Calculator::trim($refund->getNumber())) {
if (!empty($payment->original) && !$payment->getRefundedAmount()->equals($payment->original->getRefundedAmount())) {
$refund = $payment->getRefundedAmount()->subtract($payment->original->getRefundedAmount());
}
$this->logStorage->generate($payment->getOrder(), 'payment_refunded', [
'id' => $payment->id(),
'remote_id' => $payment->getRemoteId(),
'refunded_amount' => $refund,
'state' => $payment->getState()->value,
'new' => $isNew,
])->save();
}
else {
$this->logStorage->generate($payment->getOrder(), 'payment_log', [
'id' => $payment->id(),
'remote_id' => $payment->getRemoteId(),
'new' => $isNew,
'amount' => $payment->getAmount(),
'previous_amount' => $previousAmount,
'state' => $payment->getState()->value,
])->save();
}
}

}
35 changes: 35 additions & 0 deletions modules/log/src/PaymentListBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Drupal\commerce_log;

use Drupal\commerce_payment\PaymentListBuilder as BasePaymentListBuilder;

/**
* Overrides the list builder for payments.
*/
class PaymentListBuilder extends BasePaymentListBuilder {

/**
* {@inheritdoc}
*/
public function render() {
$build = parent::render();
$entities = $this->load();
/** @var \Drupal\commerce_payment\Entity\PaymentInterface $payment */
$payment = reset($entities);
if ($payment) {
$build['log']['title'] = [
'#markup' => '<h3>' . $this->t('Order activity') . '</h3>',
];
$build['log']['activity'] = [
'#type' => 'view',
'#name' => 'commerce_activity',
'#display_id' => 'default',
'#arguments' => [$payment->getOrder()->id(), 'commerce_order'],
'#embed' => FALSE,
];
}
return $build;
}

}
1 change: 1 addition & 0 deletions modules/payment/src/Entity/Payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* bundle_plugin_type = "commerce_payment_type",
* handlers = {
* "access" = "Drupal\commerce_payment\PaymentAccessControlHandler",
* "event" = "Drupal\commerce_payment\Event\PaymentEvent",
* "list_builder" = "Drupal\commerce_payment\PaymentListBuilder",
* "storage" = "Drupal\commerce_payment\PaymentStorage",
* "form" = {
Expand Down
42 changes: 42 additions & 0 deletions modules/payment/src/Event/PaymentEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Drupal\commerce_payment\Event;

use Drupal\commerce_payment\Entity\PaymentInterface;
use Symfony\Component\EventDispatcher\Event;

/**
* Defines the payment event.
*
* @see \Drupal\commerce_payment\Event\PaymentEvents
*/
class PaymentEvent extends Event {

/**
* The payment.
*
* @var \Drupal\commerce_payment\Entity\PaymentInterface
*/
protected $payment;

/**
* Constructs a new PaymentEvent.
*
* @param \Drupal\commerce_payment\Entity\PaymentInterface $payment
* The payment.
*/
public function __construct(PaymentInterface $payment) {
$this->payment = $payment;
}

/**
* Gets the payment.
*
* @return \Drupal\commerce_payment\Entity\PaymentInterface
* The payment.
*/
public function getPayment() {
return $this->payment;
}

}
67 changes: 67 additions & 0 deletions modules/payment/src/Event/PaymentEvents.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,74 @@ final class PaymentEvents {
* @Event
*
* @see \Drupal\commerce_payment\Event\FilterPaymentGatewaysEvent
*
* @var string
*/
const FILTER_PAYMENT_GATEWAYS = 'commerce_payment.filter_payment_gateways';


/**
* Name of the event fired after loading a payment.
*
* @Event
*
* @see \Drupal\commerce_payment\Event\PaymentEvent
*
* @var string
*/
const PAYMENT_LOAD = 'commerce_payment.commerce_payment.load';

/**
* Name of the event fired before saving a payment.
*
* @Event
*
* @see \Drupal\commerce_payment\Event\PaymentEvent
*
* @var string
*/
const PAYMENT_PRESAVE = 'commerce_payment.commerce_payment.presave';

/**
* Name of the event fired after saving a new payment.
*
* @Event
*
* @see \Drupal\commerce_payment\Event\PaymentEvent
*/
const PAYMENT_INSERT = 'commerce_payment.commerce_payment.insert';
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see an INSERT and a CREATE in product variation events. Do we need to duplicate the same here? The docs between the two aren't very clear about what the difference is.


/**
* Name of the event fired after saving an existing payment.
*
* @Event
*
* @see \Drupal\commerce_payment\Event\PaymentEvent
*
* @var string
*/
const PAYMENT_UPDATE = 'commerce_payment.commerce_payment.update';

/**
* Name of the event fired before deleting a payment.
*
* @Event
*
* @see \Drupal\commerce_payment\Event\PaymentEvent
*
* @var string
*/
const PAYMENT_PREDELETE = 'commerce_payment.commerce_payment.predelete';

/**
* Name of the event fired after deleting a payment.
*
* @Event
*
* @see \Drupal\commerce_payment\Event\PaymentEvent
*
* @var string
*/
const PAYMENT_DELETE = 'commerce_payment.commerce_payment.delete';

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: 'Payment events test'
type: module
package: Testing
core: 8.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
services:
payment_events_test.event_subscriber:
class: Drupal\payment_events_test\EventSubscriber
arguments: ['@state']
tags:
- { name: event_subscriber }
Loading