commerce_gc_client-8.x-1.9/src/PluginForm/PaymentOffsiteForm.php
src/PluginForm/PaymentOffsiteForm.php
<?php
namespace Drupal\commerce_gc_client\PluginForm;
use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url;
use Drupal\commerce_gc_client\GoCardlessPartner;
use Drupal\commerce_gc_client\Event\GoCardlessEvents;
use Drupal\commerce_gc_client\Event\ShipmentEvent;
use Drupal\commerce_gc_client\Event\BillingRequestFlowsEvent;
use Drupal\commerce_shipping\Entity\Shipment;
use Drupal\commerce_payment\PluginForm\PaymentOffsiteForm as BasePaymentOffsiteForm;
use Drupal\mysql\Driver\Database\mysql\Connection;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Defines the payment gateway's off-site payment form.
*/
class PaymentOffsiteForm extends BasePaymentOffsiteForm implements ContainerInjectionInterface {
/**
* The mysql database driver connection.
*
* @var \Drupal\mysql\Driver\Database\mysql\Connection
*/
private $db;
/**
* The container aware event dispatcher component.
*
* @var \Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher
*/
private $eventDispatcher;
/**
* The GoCardless Partner service.
*
* @var \Drupal\commerce_gc_client\GoCardlessPartner
*/
private $partner;
/**
* The core messenger service.
*
* @var \Drupal\Core\Messenger\Messenger
*/
private $messenger;
/**
* The Symfony current request component.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
private $currentRequest;
/**
* The core module handler extension.
*
* @var \Drupal\Core\Extension\ModuleHandler
*/
private $moduleHandler;
/**
* Constructs the PaymentOffiteForm object.
*
* @param \Drupal\mysql\Driver\Database\mysql\Connection $connection
* The database driver connection.
* @param \Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher $eventDispatcher
* The event dispatcher.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
* The module handler interface.
* @param \Drupal\commerce_gc_clinet\GoCardlessPartner $goCardlessPartner
* The GoCardless partner service.
* @param \Drupal\Core\Messenger\Messenger $messenger
* The Messenger interface.
* @param \GuzzleHttp\Client $current_request
* The GuzzleHttp client service.
*/
public function __construct(Connection $connection, ContainerAwareEventDispatcher $event_dispatcher, ModuleHandlerInterface $module_handler, GoCardlessPartner $gocardless_partner, MessengerInterface $messenger, Request $current_request) {
$this->db = $connection;
$this->eventDispatcher = $event_dispatcher;
$this->partner = $gocardless_partner;
$this->messenger = $messenger;
$this->currentRequest = $current_request;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('event_dispatcher'),
$container->get('module_handler'),
$container->get('commerce_gc_client.gocardless_partner'),
$container->get('messenger'),
$container->get('request_stack')->getCurrentRequest()
);
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$payment = $this->entity;
$payment_gateway_plugin = $payment->getPaymentGateway()->getPlugin();
$mode = $payment_gateway_plugin->getMode();
$order = $payment->getOrder();
$order_id = $order->Id();
$problem_url = Url::fromRoute('commerce_checkout.form', [
'commerce_order' => $order_id,
'step' => 'order_information',
], ['absolute' => TRUE])->toString();
// Obtain shipping data for order.
$shipment = FALSE;
if ($this->moduleHandler->moduleExists('commerce_shipping')) {
if ($shipment_id = $this->db->select('commerce_shipment', 's')
->fields('s', ['shipment_id'])
->condition('order_id', $order_id)
->execute()->fetchField()) {
$shipment = Shipment::Load($shipment_id);
}
}
$calculated_total = 0;
foreach ($order->getItems() as $item) {
$calculate = commerce_gc_client_price_calculate($order, $item);
if ($warning = $calculate['warning']) {
$this->messenger->addWarning($warning);
$this->buildRedirectForm($form, $form_state, $problem_url, []);
}
$gc = $item->getData('gc');
if (!$gc || ($gc && $gc['gc_create_payment'])) {
$calculated_total += $calculate['amount'];
}
if ($shipment) {
// Dispatch an event so that the shipping price per item can be
// added to the order item's data array.
$event = new ShipmentEvent($shipment, $item);
$this->eventDispatcher->dispatch($event, GoCardlessEvents::SHIPMENT);
if ($shipment_proportion = $event->getItemShipmentProportion()) {
if (!$data = $item->getData('gc')) {
$data = [];
}
$data['shipment'] = [
'plugin_id' => $shipment->getShippingMethod()->getPlugin()->getPluginId(),
'proportion' => $shipment_proportion,
];
$item->setData('gc', $data)->save();
}
}
}
$currency_code = $calculate['currency_code'] ? $calculate['currency_code'] : $order->getTotalPrice()->getCurrencyCode();
$this->partner->setGateway($this->entity->getPaymentGatewayId());
$redirect_url = $this->partner->settings['partner_url'] . '/gc_partner/mandate?payment_method=gocardless_client&order_id=' . $order_id . '&complete_path=' . $form['#return_url'];
// Generate the mandate_details array.
$prefilled_customer = ['email' => $order->getEmail()];
if ($profile = $order->getBillingProfile()) {
$billing_country = $profile->address->country_code;
$prefilled_customer += [
'given_name' => $profile->address->given_name,
'family_name' => $profile->address->family_name,
'company_name' => $profile->address->organisation,
'address_line1' => $profile->address->address_line1,
'address_line2' => $profile->address->address_line2,
'city' => $profile->address->locality,
'postal_code' => $profile->address->postal_code,
'country_code' => $billing_country,
];
}
// Determine if payment and mandate requests are required.
$use_instant_payments = $this->partner->settings['configuration']['instant_payments'];
$payment_request = false;
$mandate_request = false;
foreach ($order->getItems() as $item) {
// Any order item with recurring rules set requires a mandate.
if ($gc = $item->getData('gc')) {
$mandate_request = true;
// Instant payment only required for One-off payments if instructed
// to create payment immediately.
if ($use_instant_payments && $gc['gc_type'] == 'P' && $gc['gc_create_payment']) {
$payment_request = true;
}
}
// Otherwise it is a payment request. Note that payment requests are
// only currently available for GBP and EUR, and if the order has a
// different currency a mandate request will be automatically generated
// instead.
elseif ($use_instant_payments) {
$payment_request = true;
}
}
$data = [
'endpoint' => 'billing_request_flows',
'action' => 'create',
'order_id' => $order_id,
'base_url' => $this->currentRequest->getSchemeAndHttpHost(),
'redirect_path' => '/checkout/' . $order_id . '/payment/return',
'exit_path' => '/checkout/' . $order_id . '/payment/cancel',
'prefilled_customer' => $prefilled_customer,
];
if ($payment_request) {
$data['payment_request'] = [
'description' => 'Order #' . $order_id,
'amount' => $calculated_total * 100,
'currency' => $calculate['currency_code'],
'country' => $calculate['country_code'],
];
}
if ($mandate_request) {
$data['mandate_request'] = ['scheme' => $calculate['scheme']];
}
// Dispatch an event so that the billing_request_flow data can be altered
// by other modules.
$event = new BillingRequestFlowsEvent($data, $order);
$this->eventDispatcher->dispatch($event, GoCardlessEvents::BILLING_REQUEST_FLOWS);
$data = $event->getBillingRequestFlow();
$result = $this->partner->api($data);
if (isset($result->response) && UrlHelper::isValid($result->response)) {
$redirect_url = $result->response;
$this->buildRedirectForm($form, $form_state, $redirect_url, []);
}
else {
$this->messenger->addError($this->t('Something went wrong during checkout with GoCardless and your order has not been completed.'));
$this->buildRedirectForm($form, $form_state, $problem_url, []);
}
return $form;
}
}
