commerce_gc_client-8.x-1.9/src/Form/Mandate.php

src/Form/Mandate.php
<?php

namespace Drupal\commerce_gc_client\Form;

use Drupal\commerce_gc_client\GoCardlessPartner;
use Drupal\commerce_gc_client\Event\GoCardlessEvents;
use Drupal\commerce_gc_client\Event\PaymentCreatedEvent;
use Drupal\commerce_price\Entity\Currency;
use Drupal\commerce_price\CurrencyFormatter;
use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_order\Entity\OrderItem;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Ajax\RedirectCommand;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Url;
use Drupal\mysql\Driver\Database\mysql\Connection;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;

/**
 * Defines a form for managing GoCardless mandates for order items.
 */
class Mandate extends FormBase {

  /**
   * The current Request Stack.
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $currentRequest;

  /**
   * The database driver connection.
   *
   * @var \Drupal\mysql\Driver\Database\mysql\Connection
   */
  protected $db;

  /**
   * The date formatter service.
   *
   * @var \Drupal\Core\Datetime\DateFormatterInterface
   */
  protected $dateFormatter;

  /**
   * The currency formatter service.
   *
   * @var Drupal\commerce_price\CurrencyFormatter
   */
  protected $currencyFormatter;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $config;

  /**
   * The event dispatcher.
   *
   * @var \Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher
   */
  protected $eventDispatcher;

  /**
   * The commerce order ID for the form.
   *
   * @var int
   */
  protected $orderId;

  /**
   * The modules's GoCardless IDs for the order items.
   *
   * @var array
   */
  protected $gcs;

  /**
   * The GoCardless Partner service.
   *
   * @var \Drupal\commerce_gc_client\GoCardlessPartner
   */
  protected $partner;

  /**
   * The currency code for the Commerce order.
   *
   * @var string
   */
  protected $commerceCurrencyCode;

  /**
   * The module's currency definition for the Commerce order.
   *
   * @var array
   */
  protected $gcCurrency;

  /**
   * The GoCardless mandate's currency code.
   *
   * @var string
   */
  protected $currencyCode;

  /**
   * List of items contained in order for select list.
   *
   * @var array
   */
  protected $itemSelect;

  /**
   * The selected Commerce order item ID.
   *
   * @var int
   */
  protected $itemId;

  /**
   * The modules's GoCardless data for the selected order item.
   *
   * @var object
   */
  protected $gc;

  /**
   * The GoCardless.com mandate for the order.
   *
   * @var object
   */
  protected $mandate;

  /**
   * The selected Commerce order item.
   *
   * @var Drupal\commerce_order\Entity\OrderItem
   */
  protected $item;

  /**
   * The default amount for the selected order item.
   *
   * @var string
   */
  protected $defaultAmount;

  /**
   * The default name for the selected order item.
   *
   * @var string
   */
  protected $defaultName;

  /**
   * The time service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * Constructs a new Mandate object.
   *
   * @param \GuzzleHttp\Client $current_request
   *   The GuzzleHttp client service.
   * @param \Drupal\mysql\Driver\Database\mysql\Connection $connection
   *   The database driver connection.
   * @param \Drupal\commerce_price\CurrencyFormatter $currencyFormatter
   *   The Commerce currency formatter service.
   * @param \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter
   *   The date formatter service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   * @param \Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher $eventDispatcher
   *   The event dispatcher.
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The time service.
   * @param \Drupal\commerce_gc_clinet\GoCardlessPartner $goCardlessPartner
   *   The GoCardless partner service.
   */
  public function __construct(Request $current_request, Connection $connection, CurrencyFormatter $currencyFormatter, DateFormatterInterface $dateFormatter, ConfigFactoryInterface $configFactory, ContainerAwareEventDispatcher $eventDispatcher, TimeInterface $time, GoCardlessPartner $goCardlessPartner) {
    $this->currentRequest = $current_request;
    $this->db = $connection;
    $this->currencyFormatter = $currencyFormatter;
    $this->dateFormatter = $dateFormatter;
    $this->config = $configFactory->get('commerce_gc_client.settings')->get();
    $this->eventDispatcher = $eventDispatcher;
    $this->time = $time;
    $this->partner = $goCardlessPartner;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('request_stack')->getCurrentRequest(),
      $container->get('database'),
      $container->get('commerce_price.currency_formatter'),
      $container->get('date.formatter'),
      $container->get('config.factory'),
      $container->get('event_dispatcher'),
      $container->get('datetime.time'),
      $container->get('commerce_gc_client.gocardless_partner')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'commerce_gc_client_mandate_form';
  }

  /**
   * Form constructor.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $order = $this->getRouteMatch()->getParameter('commerce_order');
    
    // If it is a recurring order, then use the parent order instead, but only
    // use the relevant order item.
    $is_recurring = FALSE;
    if ($order_gc = $order->getData('gc')) {
      if (isset($order_gc['parent'])) {
        $order = Order::load($order_gc['parent']);
        $item = OrderItem::load($order_gc['item_id']);
        $order->setItems([$item]);
        $is_recurring = 'child';
      }
      else {
        $is_recurring = 'parent';
      }
    }
      
    $payment_gateway_id = $order->get('payment_gateway')->first()->entity->Id();
    $this->partner->setGateway($payment_gateway_id);
    $this->orderId = $order->id();
    $query = $this->db->select('commerce_gc_client', 'g');
    $query->join('commerce_gc_client_item', 'i', 'i.gcid=g.gcid');
    $this->gcs = $query
      ->fields('g')
      ->fields('i')
      ->condition('order_id', $this->orderId)
      ->execute()
      ->fetchAllAssoc('item_id');

    $count = $is_recurring == 'child' ? 1 : count($this->gcs);
    
    if ($count == 0) {
      $message = $this->t('You have no GoCardless mandates associated with this order.');
      $payment_gateway_id = $order->payment_gateway->entity->Id();
      if ($order->payment_gateway->entity->getPluginId() == 'gocardless_client') {
        $message .= $this->t(' Check the "Payments" tab for details of Instant Payments.');
      }
      $this->messenger()->addWarning($message);
      return;
    }

    if ($total_price = $order->getTotalPrice()) {
      $this->commerceCurrencyCode = $total_price->getCurrencyCode();
      $commerce_currency_symbol = Currency::load($this->commerceCurrencyCode)->getSymbol();
    }
    foreach ($this->config['currency_schemes'] as $this->currencyCode => $this->gcCurrency) {
      if ($this->gcCurrency['scheme'] == reset($this->gcs)->gc_mandate_scheme) {
        $currency_symbol = Currency::load($this->currencyCode)->getSymbol();
        break;
      }
    }

    // Create an array of unique line item names.
    $this->itemSelect = [];
    $title_count = [];
    $items = $order->getItems();
      
    foreach ($this->gcs as $gc) {
      $item = OrderItem::load($gc->item_id);
      $select_id = $gc->item_id;
      $item_title = $item ? $item->getTitle() : $gc->item_id;
      !isset($title_count[$item_title]) ? $title_count[$item_title] = 1 : $title_count[$item_title]++;
      $title[$select_id] = $title_count[$item_title] == 1 ? $item_title : $item_title . ' (' . $title_count[$item_title] . ')';
      $this->itemSelect[$select_id] = $title[$select_id];
    }
  
    if ($count == 1) {
      $this->itemId = reset($this->gcs)->item_id;
      $this->item = reset($items);
      $item_title = isset($item_title) ? $item_title : t('Unknown');
      if ($is_recurring == 'child') {
        $params = ['@link' => $order->toLink('Order #'. $order->id())->toString()];
        $text_top = t('<h3><b>Created as a recurring payment from @link</b></h3>', $params);
      }
      else {
        $text_top = t('<h3><b>Administrate @title</b></h3>', [
          '@title' => $item_title,
        ]);
      }
    }
    else {
      if ($item_id = $this->currentRequest->query->get('item_id')) {
        $this->itemId = $item_id;
      }
      else {
        $this->itemId = reset($this->gcs)->item_id;
      }
      $this->item = OrderItem::load($this->itemId);
      $form = ['#attributes' => ['id' => ['switch-item']]];
      $text_top = t('<h3><b>Administrate @title</b></h3>', [
        '@title' => $this->itemSelect[$this->itemId],
      ]);
    }
    if (!$this->item) {
      $text_top .= t('<div class="messages messages--warning">This order item appears to have been deleted.</div>');        
    }
    
    $form['text_top'] = [
      '#type' => 'item',
      '#markup' => $text_top,
    ];
    if ($count > 1) {
      $form['item_id'] = [
        '#type' => 'value',
        '#value' => $this->itemId,
      ];
      $form['order_id'] = [
        '#type' => 'value',
        '#value' => $this->orderId,
      ];
      $form['item_id'] = [
        '#title' => $this->t('Switch item'),
        '#type' => 'select',
        '#options' => $this->itemSelect,
        '#default_value' => $this->itemId,
        '#ajax' => [
          'callback' => [$this, 'switchItem'],
          'wrapper' => 'switch-item',
          'method' => 'replace',
        ],
      ];
    }

    $this->gc = $this->gcs[$this->itemId];
    
    $result = $this->partner->api([
      'endpoint' => 'mandates',
      'action' => 'get',
      'mandate' => $this->gc->gc_mandate_id,
    ]);
    
    if (!$result || !$result->response || $result->response->status_code != 200) {
      $this->messenger()->addWarning($this->t('No active mandate found for this order at GoCardless.'));
      return;
    }
    else {
      $this->mandate = $result->response->body->mandates;
    }

    if ($this->item) {
      $total = $this->item->getTotalPrice()->getNumber();
      $data = $this->item->getData('gc');
      $this->defaultAmount = number_format((float) $total, 2, '.', '');
      $interval = isset($data['interval_params']) ? $data['interval_params']['string'] : NULL;
    }
    else {
      $interval = NULL;
      $data = [];
    }

    if (isset($data['shipment'])) {
      foreach ($order->getAdjustments() as $adj) {
        if ($adj->getType() == 'shipping') {
          $adj_amount = $adj->getAmount()->getNumber();
          $shipment_currency_code = $adj->getAmount()->getCurrencyCode();
          $shipment_amount = round($adj_amount * $data['shipment']['proportion'], 2);
          $this->defaultAmount += $shipment_amount;
          $shipment_arr = [
            'Shipping' => $this->currencyFormatter->format($shipment_amount, $shipment_currency_code),
          ];
          break;
        }
      }
    }

    if ($is_recurring == 'child' && isset($order_gc['gc_payment_id'])) {
      $result = $this->partner->api([
        'endpoint' => 'payments',
        'action' => 'get',
        'id' => $order_gc['gc_payment_id'],
      ]);
      if ($result && $result->response->status_code == 200) {
        $payments = [$result->response->body->payments];
      }
    }
    else {
      $result = $this->partner->api([
        'endpoint' => 'payments',
        'action' => 'list',
        'mandate' => $this->gc->gc_mandate_id,
        'limit' => 500,
      ]);
      if ($result && $result->response->status_code == 200) {
        $payments = $result->response->body->payments;
      }
    }

    // Data for one-off payments.
    if ($this->gc->type == 'P') {
      $item_data = [
        'Mandate ID' => Html::escape($this->mandate->id),
        'Mandate status' => Html::escape(ucfirst($this->mandate->status)),
        'Created' => $this->dateFormatter->format(strtotime($this->mandate->created_at), 'short'),
        'Type' => $this->t('Payments'),
        'Amount' => isset($total) ? $this->currencyFormatter->format($total, $this->commerceCurrencyCode) : t('Unknown'),
      ];
      if (isset($shipment_arr)) {
        $item_data += $shipment_arr;
      }
      $item_data += [
        'Interval' => $interval == ' ' ? '-' : $interval,
        'Next possible charge date' => !is_null($this->mandate->next_possible_charge_date) ? $this->dateFormatter->format(strtotime($this->mandate->next_possible_charge_date), 'short') : '-',
        'Next scheduled payment creation' => $this->mandate->status != 'cancelled' && !is_null($this->gc->next_payment) ? $this->dateFormatter->format($this->gc->next_payment, 'short') : '-',
      ];
      if (array_key_exists('gc_end_type', $data)) {
        if ($data['gc_end_type'] == 'count') {                  
          $remaining = $data['gc_count'];
          if (array_key_exists('gc_count_remaining', $data)) {
            $remaining = $data['gc_count_remaining'];
          }
          $count = t('@remaining of @count payments remaining', [
            '@remaining' => $remaining,
            '@count' => $data['gc_count'],
          ]);
          $item_data += ['Count' => $count];
        }
        if ($data['gc_end_type'] == 'fixed' || $data['gc_end_type'] == 'relative') {
          $final_payment = t('Before the end of @end_time', [
            '@end_time' => $this->dateFormatter->format(strtotime($data['gc_end_date']), 'short'),
          ]);
          $item_data += ['Final payment creation' => $final_payment];
        }
      }
      $this->defaultName = !$this->item ?: $this->itemSelect[$this->itemId];
    }

    // Data for subscriptions table.
    elseif ($this->gc->type == 'S') {
      $this->subscription = [];
      if ($this->gc->gc_subscription_id) {
        $result = $this->partner->api([
          'endpoint' => 'subscriptions',
          'action' => 'get',
          'id' => $this->gc->gc_subscription_id,
        ]);
        if ($result->response->status_code == 200) {
          $this->subscription = $result->response->body->subscriptions;
        }
      }

      if (!is_object($this->subscription) || !$this->gc->gc_subscription_id) {
        $form['no_subscription'] =[
          '#markup' => t('<div class="messages messages--warning">No subscription found at GoCardless for this line item.</div>'),
          '#weight' => 0,
        ];
        return $form;
      }

      $item_data = [
        'Mandate ID' => Html::escape($this->mandate->id),
        'Mandate status' => Html::escape(ucfirst($this->mandate->status)),
        'Created' => $this->dateFormatter->format(strtotime($this->mandate->created_at), 'gocardless_client'),
        'Type' => $this->t('Subscription'),
        'Subscription status' => Html::escape(ucfirst($this->subscription->status)),
        'Subscription name' => Html::escape($this->subscription->name),
        'Subscription ID' => Html::escape($this->subscription->id),
        'Subscription start' => $this->dateFormatter->format(strtotime($this->subscription->start_date), 'gocardless_client'),
        'Amount' => $this->currencyFormatter->format($total, $this->commerceCurrencyCode),
      ];
      if (isset($shipment_arr)) {
        $item_data += $shipment_arr;
      }
      $item_data += [
        'Interval' => $interval,
        'Day of month' => Html::escape($this->subscription->day_of_month),
        'Month' => ucfirst(Html::escape($this->subscription->month)),
        'End date' => !is_null($this->subscription->end_date) ? $this->dateFormatter->format(strtotime($this->subscription->end_date), 'gocardless_client') : NULL,
      ];

      // Assemble data for upcoming payments table.
      $upcoming_rows = [];
      foreach ($this->subscription->upcoming_payments as $upcoming) {
        $upcoming_rows[] = [
          $this->dateFormatter->format(strtotime($upcoming->charge_date), 'gocardless_client'),
          $this->currencyFormatter->format($upcoming->amount / 100, $this->currencyCode),
        ];
      }
      $this->defaultName = Html::escape($this->subscription->name);
    }

    $item_rows = [];
    foreach ($item_data as $item_data_key => $item_data_data) {
      if (is_null($item_data_data)) {
        continue;
      }
      $item_rows[] = [
        $this->t('@key', ['@key' => $item_data_key]),
        $item_data_data,
      ];
      if ($is_recurring == 'child' &&  $item_data_key == 'Type') {
        break;
      }
    }
    
    $payment_rows = [];
    $payment_total = 0;
    $renderer = \Drupal::service('renderer');
    if (isset($payments)) {
      foreach ($payments as & $payment) {
        if (isset($payment->links->subscription) && $payment->links->subscription != $this->gc->gc_subscription_id || isset($payment->metadata->item_id) && $payment->metadata->item_id != $this->itemId) {
          continue;
        }

        // Assemble an Actions dropbutton.
        $actions = ['#type' => 'dropbutton'];
        if ($payment->status == 'pending_submission') {
          $url = new Url(
            'commerce_gc_client.payment_cancel_form', [
            'commerce_order' => $this->orderId,
            'payment_id' => $payment->id,
          ]);
          $actions['#links']['cancel'] = [
            'title' => $this->t('Cancel'), 
            'url' => $url,
          ];
        }
        if ($is_recurring == 'parent' && isset($order_gc['children'][$payment->id])) {
          $url = new Url(
            'commerce_gc_client.mandate', [
            'commerce_order' => $order_gc['children'][$payment->id],
          ]);
          $actions['#links']['child'] = [
            'title' => $this->t('View recurring'), 
            'url' => $url,
          ];
        }
        elseif ($is_recurring == 'child' && isset($order_gc['parent'])) {
          $url = new Url('commerce_gc_client.mandate',
            ['commerce_order' => $order_gc['parent']],
            ['query' => ['item_id' => $order_gc['item_id']]]
          );
          $actions['#links']['child'] = [
            'title' => $this->t('View parent item'), 
            'url' => $url,
          ];
        }
        
        $payment_rows[$payment->id] = [
          $this->dateFormatter->format(strtotime($payment->created_at), 'short'),
          Html::escape($payment->description),
          Html::escape($payment->id),
          $this->currencyFormatter->format($payment->amount / 100, $this->currencyCode),
          Html::escape($payment->status),
          $this->dateFormatter->format(strtotime($payment->charge_date), 'gocardless_client'),
          $renderer->render($actions),
        ];

        if ($payment->status == 'confirmed' || $payment->status == 'paid_out') {
          $payment_total += $payment->amount / 100;
        }
      }
    }

    $item_header = [[
      'data' => 'Item data',
      'colspan' => 2,
      'style' => 'text-align:center;font-weight:bold;',
    ]];

    $form['table'] = [
      '#type' => 'table',
      '#header' => $item_header,
      '#rows' => isset($item_rows) ? $item_rows : NULL,
      '#empty' => $this->t('There are no GoCardless items for this order'),
      '#prefix' => '<div id="gc-item-table">',
      '#suffix' => '</div>',
      '#attached' => ['library' => ['commerce_gc_client/gocardless-client']],
    ];

    if ($this->gc->type == 'S') {
      $form['upcoming_payments'] = [
        '#type' => 'details',
        '#title' => $this->t('Upcoming payments'),
        '#open' => FALSE,
        '#prefix' => '<div id="gc-upcoming-payments-details">',
        '#suffix' => '</div>',
      ];
      $upcoming_header = [$this->t('Charge date'), $this->t('Amount')];
      $form['upcoming_payments']['upcoming_payments_table'] = [
        '#theme' => 'table',
        '#header' => $upcoming_header,
        '#rows' => isset($upcoming_rows) ? $upcoming_rows : NULL,
        '#empty' => $this->t('There are no upcoming payments for this subscription.'),
      ];
    }

    if (isset($payment_rows)) {
      $form['payment_tables'] = [
        '#type' => 'details',
        '#title' => $this->t('Payments'),
        '#description' => $this->t('(Live data from GoCardless.com)'),
        '#open' => TRUE,
      ];
      $payment_header = [
        $this->t('Created'),
        $this->t('Description'),
        $this->t('Payment ID'),
        $this->t('Amount'),
        $this->t('Status'),
        $this->t('Charge customer at'),
        '',
      ];

      $empty = 'No payments have been created for the item yet.';
      if ($this->gc->type == 'P') {
        $empty .= ' Please check the "Payments" tab for details, if an Instant Payment was created during checkout.';
      }
      $form['payment_tables']['payments_table'] = [
        '#theme' => 'table',
        '#header' => $payment_header,
        '#rows' => isset($payment_rows) ? $payment_rows : NULL,
        '#empty' => $this->t($empty),
        '#suffix' => $this->t('Total confirmed payments: @payment_total', [
          '@payment_total' => $this->currencyFormatter->format($payment_total, $this->currencyCode),
        ]),
      ];
    }

    // If the order items have been removed or it is a recurring child order
    // then we do not want the administration tools.
    if (!$this->item || $is_recurring == 'child') {
      return $form;
    }

    // Create payment subform.
    if (in_array($this->mandate->status, [
      'pending_submission',
      'submitted',
      'active',
    ])) {
      $this->paymentCreateSubform($form, $form_state, $data, $currency_symbol);
    }

    if ($this->gc->type == 'S') {
      if ($this->subscription->status != 'cancelled') {

        // Update subscription section.
        $this->subscriptionUpdateSubform($form, $form_state, $data, $currency_symbol);

        // Cancel subscription button.
        $subscription_cancel_message = $this->t('Are you sure you want to cancel this subscription?');
        $form['cancel_subscription'] = [
          '#type' => 'submit',
          '#value' => $this->t('Cancel subscription at GoCardless'),
          '#submit' => [[$this, 'subscriptionCancelSubmit']],
          '#attributes' => [
            'onclick' => 'if (!confirm("' . $subscription_cancel_message . '")) {return false;}',
          ],
        ];
      }
    }

    if ($this->gc->type == 'P') {
      if ($this->gc->gc_mandate_status !== 'cancelled') {

        // Update payment creation section.
        $this->paymentUpdateSubform($form, $form_state, $data, $commerce_currency_symbol, $total);
               
        // Recurring orders section.
        $this->recurringSubform($form, $form_state, $data);
      }        

      // Schedule adjustments section.
      $this->scheduledAdjustmentsSubform($form, $form_state, $currency_symbol);
    }
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {}

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {}

  /**
   * Update Subscription subform.
   *
   * @param array $form
   *   The form.
   * @param object $form_state
   *   The form_state object.
   * @param array $data
   *   Array of module specific data for order item.
   * @param string $currency_symbol
   *   The currency symbol relevant to the mandate.
   * 
   * @return void
   */
  private function subscriptionUpdateSubform(&$form, $form_state, $data, $currency_symbol) {
    $form['update_subscription'] = [
      '#type' => 'details',
      '#title' => $this->t('Update subscription'),
      '#open' => $this->currentRequest->query->get('action') == 'subscription_update',
    ];
    $form['update_subscription']['subscription_name'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Subscription name'),
      '#default_value' => $this->defaultName,
    ];
    $form['update_subscription']['subscription_amount'] = [
      '#type' => 'number',
      '#title' => $this->t('Amount') . ' ' . $currency_symbol,
      '#size' => 10,
      '#default_value' => $this->defaultAmount,
      '#min' => 1,
      '#step' => .01,
    ];
    if (isset($data['shipment'])) {
      $form['update_subscription']['shipment'] = [
        '#type' => 'number',
        '#title' => $this->t('Shipping proportion %'),
        '#description' => $this->t("The proportion of the order's total shipping amount to allocate to this item."),
        '#size' => 5,
        '#default_value' => round($data['shipment']['proportion'] * 100, 2),
        '#step' => .01,
        '#min' => 0,
      ];
    }
    $form['update_subscription']['subscription_submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Update subscription details at GoCardless'),
      '#submit' => [[$this, 'subscriptionUpdateSubmit']],
    ];
  }

  /**
   * Subscription Update submit.
   */
  public function subscriptionUpdateSubmit(array &$form, FormStateInterface $form_state) {
    $shipment = $form_state->getValue('shipment');
    if ($shipment || $shipment == 0) {
      $gc = $this->item->getData('gc');
      if ($gc['shipment']['proportion'] != (float) $shipment / 100) {
        $gc['shipment']['proportion'] = (float) $shipment / 100;
        $this->item->setData('gc', $gc);
        $this->item->save();
        $this->messenger()->addMessage($this->t('Shipping proportion has been updated for the item.'));
      }
    }

    // Only update the subscription at GoCardless if the amount or the name
    // have been changed, since this action can only be done a limited number
    // of times.
    $amount = $form_state->getValue('subscription_amount');
    $name = $form_state->getValue('subscription_name');
    if ($amount * 100 != $this->subscription->amount || $name != $this->defaultName) {
      $result = $this->partner->api([
        'endpoint' => 'subscriptions',
        'action' => 'update',
        'id' => $this->gc->gc_subscription_id,
        'amount' => $form_state->getValue('subscription_amount') * 100,
        'name' => $form_state->getValue('subscription_name'),
      ]
      );
      if ($result->response->status_code == 200) {
        $this->messenger()->addMessage($this->t('Subscription was updated successfully at GoCardless.'));
      }
      else {
        $this->messenger()->addWarning($this->t('There was a problem updating the subscription at GoCardless.'));
      }
    }
    $form_state->setRedirect('commerce_gc_client.mandate', ['commerce_order' => $this->orderId], ['query' => [
      'item_id' => $this->itemId,
      'action' => 'subscription_update',
    ]]);
  }

  /**
   * Subscription Cancellation submission.
   */
  public function subscriptionCancelSubmit(array &$form, FormStateInterface $form_state) {
    $result = $this->partner->api([
      'endpoint' => 'subscriptions',
      'action' => 'cancel',
      'id' => $this->gc->gc_subscription_id,
    ]
    );
    if ($result->response->status_code == 200) {
      $this->messenger()->addMessage($this->t('Subscription was cancelled successfully. Please review any pending payments and cancel if necessary.'));
    }
    else {
      $this->messenger()->addWarning($this->t('There was a problem cancelling the subscription with GoCardless.'));
    }
    $form_state->setRedirect('commerce_gc_client.mandate', ['commerce_order' => $this->orderId], ['query' => [
      'item_id' => $this->itemId,
    ]]);
  }

  /**
   * Update Payment subform.
   *
   * @param array $form
   *   The form.
   * @param object $form_state
   *   The form_state object.
   * @param array $data
   *   Array of module specific data for order item.
   * @param string $currency_symbol
   *   The currency symbol relevant to the mandate.
   * 
   * @return void
   */
  private function paymentCreateSubform(&$form, $form_state, $data, $currency_symbol) {
    $form['create_payment'] = [
      '#type' => 'details',
      '#title' => $this->t('Create a payment'),
      '#open' => $this->currentRequest->query->get('action') == 'payment_create',
    ];
    if ($this->gc->type == 'S') {
      $form['create_payment']['#description'] = $this->t('You can create one-off payments under the existing mandate for this item, which are in addition to the subscription plan listed here.');
    }
    $form['create_payment']['payment_amount'] = [
      '#type' => 'number',
      '#title' => $this->t('Amount') . ' ' . $currency_symbol,
      '#size' => 10,
      '#default_value' => $this->defaultAmount,
      '#min' => 1,
      '#step' => .01,
    ];
    $form['create_payment']['payment_title'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Payment title'),
      '#default_value' => $this->t('Payment for @default_name', [
        '@default_name' => $this->defaultName,
      ]),
    ];
    $form['create_payment']['charge_date'] = [
      '#title' => $this->t('Charge customer at'),
      '#type' => 'date',
      '#default_value' => date('Y-m-d', strtotime($this->mandate->next_possible_charge_date)),
    ];
    $form['create_payment']['payment_submit'] = [
      '#type' => 'submit',
      '#value' => 'Instruct GoCardless to create a Payment',
      '#validate' => [[$this, 'paymentCreateValidate']],
      '#submit' => [[$this, 'paymentCreateSubmit']],
      '#attributes' => [
        'onclick' => 'if (!confirm("Are you sure you want to create a payment with GoCardless?")) {return false;}',
      ],
    ];
  }
  
  /**
   * Create Payment form validation.
   */
  public function paymentCreateValidate(array &$form, FormStateInterface $form_state) {
    // Check that specified date is greater than or equal to the next possible
    // charge date.
    if (!empty($form_state->getValue('charge_date'))) {
      if (strtotime($form_state->getValue('charge_date')) < strtotime($this->mandate->next_possible_charge_date)) {
        $form_state->setErrorByName('charge_date', $this->t("The date cannot be before the 'Next Possible Charge Date'."));
      }
    }
  }

  /**
   * Create Payment form submission.
   */
  public function paymentCreateSubmit(array &$form, FormStateInterface $form_state) {
    $amount = $form_state->getValue('payment_amount');
    !empty($form_state->getValue('payment_title')) ? $title = $form_state->getValue('payment_title') : $title = $this->default_title;

    $result = $this->partner->api([
      'endpoint' => 'payments',
      'action' => 'create',
      'mandate' => $this->mandate->id,
      'amount' => $amount,
      'currency' => $this->currencyCode,
      'description' => $title,
      'charge_date' => $form_state->getValue('charge_date'),
      'metadata' => ['item_id' => $this->itemId],
    ]);
    if (!isset($result->response)) {
      $this->messenger()->addWarning($this->t('There was a problem creating the payment with GoCardless'));
      return;
    }
    elseif ($result->response->status_code == 201) {
      $payment = $result->response->body->payments;
      $this->messenger()->addMessage($this->t('Payment created successfully with GoCardless'));
    }

    $form_state->setRedirect('commerce_gc_client.mandate', ['commerce_order' => $this->orderId], ['query' => [
      'item_id' => $this->itemId,
      'action' => 'payment_create',
    ]]);

    // Dispatch an event so that other modules can respond to payment creation.
    if (isset($payment)) {
      $event = new PaymentCreatedEvent($payment, $this->itemId, 'manual');
      $this->eventDispatcher->dispatch($event, GoCardlessEvents::PAYMENT_CREATED);
    }    
  }

  /**
   * Update Payment subform.
   *
   * @param array $form
   *   The form.
   * @param object $form_state
   *   The form_state object.
   * @param array $data
   *   Array of module specific data for order item.
   * 
   * @return void
   */
  private function paymentUpdateSubform(&$form, $form_state, $data, $commerce_currency_symbol, $total) {
    $gc_end_type = 'none';
    $count = null;
    $remaining = null;
    $end_date = null;
    if (array_key_exists('gc_end_type', $data)) {
      $gc_end_type = $data['gc_end_type'];
      $count = $data['gc_count'];
      $remaining = $data['gc_count'];
      if (array_key_exists('gc_count_remaining', $data)) {
        $remaining = $data['gc_count_remaining'];
      }
      $end_date = $data['gc_end_date'];
    }

    $form['update_payment'] = [
      '#type' => 'details',
      '#title' => $this->t('Update scheduled payments creation'),
      '#open' => $this->currentRequest->query->get('action') == 'payment_update',
    ];
    $form['update_payment']['next_payment'] = [
      '#type' => 'datetime',
      '#default_value' => $this->gc->next_payment ? DrupalDateTime::createFromTimestamp($this->gc->next_payment) : NULL,
      '#date_year_range' => '0:+10',
      '#description' => $this->t('Change the date that the next scheduled payment will be created. (This is not the same date that the customer will be charged on.)'),
    ];
    $form['update_payment']['interval_length'] = [
      '#type' => 'number',
      '#title' => $this->t('Interval length'),
      '#size' => 3,
      '#maxlength' => 3,
      '#default_value' => isset($data['interval_params']) ? $data['interval_params']['length'] : NULL,
      '#min' => 1,
    ];
    $form['update_payment']['interval_unit'] = [
      '#type' => 'select',
      '#title' => $this->t('Interval unit'),
      '#default_value' => isset($data['interval_params']) ? $data['interval_params']['unit'] : NULL,
      '#options' => [
        'weekly' => $this->t('Week'),
        'monthly' => $this->t('Month'),
        'yearly' => $this->t('Year'),
      ],
      '#empty_option' => $this->t('- select -'),
    ];
    $form['update_payment']['amount'] = [
      '#type' => 'number',
      '#title' => $this->t('Amount') . ' ' . $commerce_currency_symbol,
      '#size' => 5,
      '#default_value' => number_format((float) $total, 2, '.', ''),
      '#step' => .01,
      '#min' => 0,
      '#disabled' => TRUE,
    ];
    if (isset($data['shipment'])) {
      $form['update_payment']['shipment'] = [
        '#type' => 'number',
        '#title' => $this->t('Shipping proportion %'),
        '#description' => $this->t("The proportion of the order's total shipping amount to allocate to this item."),
        '#size' => 5,
        '#default_value' => round($data['shipment']['proportion'] * 100, 2),
        '#step' => .01,
        '#min' => 0,
      ];
    }
    $form['update_payment']['final_payment'] = [
      '#type' => 'details',
      '#title' => $this->t('Final payment'),
      '#open' => $gc_end_type == 'none' ? FALSE : TRUE,
    ];
    $form['update_payment']['final_payment']['gc_end_type'] = [
      '#type' => 'select',
      '#title' => $this->t('Setting the final payment creation'),
      '#default_value' => $gc_end_type,
      '#options' => [
        'none' => $this->t('There is no final payment'),
        'count' => $this->t('After a specific number of payments'),
        'fixed' => $this->t('Specific date'),
      ],
    ];
    $form['update_payment']['final_payment']['gc_count'] = [
      '#type' => 'number',
      '#title' => $this->t('Count'),
      '#size' => 5,
      '#default_value' => $count,
      '#min' => 1,
      '#description' => t('The number of automatic payments that will be created from this point on.'),
      '#states' => [
        'visible' => [
          ':input[id="edit-gc-end-type"]' => [
            'value' => 'count',
          ],
        ],
      ],
    ];
    $form['update_payment']['final_payment']['gc_count_remaining'] = [
      '#type' => 'number',
      '#title' => $this->t('Remaining'),
      '#size' => 5,
      '#default_value' => $remaining,
      '#min' => 0,
      '#description' => t('The number of automatic payments remaining.'),
      '#states' => [
        'visible' => [
          ':input[id="edit-gc-end-type"]' => [
            'value' => 'count',
          ],
        ],
      ],
    ];
    $form['update_payment']['final_payment']['gc_end_date'] = [
      '#type' => 'date',
      '#default_value' => $end_date,
      '#datepicker_options' => ['minDate' => 0],
      '#description' => $this->t('Date on or after which no further payments will be created.'),
      '#states' => [
        'visible' => [
          ':input[id="edit-gc-end-type"]' => [
            'value' => 'fixed',
          ],
        ],
        'required' => [
          ':input[id="edit-gc-end-type"]' => [
            'value' => 'fixed',
          ],
        ],
      ],
    ];
    $form['update_payment']['update_payment_button'] = [
      '#type' => 'submit',
      '#value' => 'Update schedule',
      '#validate' => [[$this, 'paymentUpdateValidate']],
      '#submit' => [[$this, 'paymentUpdateSubmit']],
    ];
  }

  /**
   * Update Payment form validation.
   */
  public function paymentUpdateValidate(array &$form, FormStateInterface $form_state) {
    $interval_length = $form_state->getValue('interval_length');
    $interval_unit = $form_state->getValue('interval_unit');
    if (empty($interval_length) && !empty($interval_unit)) {
      $form_state->setErrorByName('interval_length', $this->t("An interval length must be selected as well as the interval unit."));
    }
    if (!empty($interval_length) && empty($interval_unit)) {
      $form_state->setErrorByName('interval_unit', $this->t("An interval unit must be selected as well as the interval length."));
    }
  }

  /**
   * Update Payment form submission.
   */
  public function paymentUpdateSubmit(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    $next_payment = $values['next_payment'] ? strtotime($values['next_payment']) : NULL;
    $this->db->update('commerce_gc_client_item')
      ->fields([
        'next_payment' => $next_payment,
      ])
      ->condition('item_id', $this->itemId)
      ->execute();

    $interval_length = $values['interval_length'];
    $interval_unit = $values['interval_unit'];
    $gc = $this->item->getData('gc');
    if ($interval_length) {
      $gc['interval_params'] = [
        'length' => $interval_length,
        'unit' => $interval_unit,
        'string' => $interval_length . ' ' . str_replace("ly", "", $interval_unit),
        'gc' => $interval_length . ' ' . $interval_unit,
      ];
    }

    $shipment = $form_state->getValue('shipment');
    if ($shipment || $shipment === 0) {
      $gc['shipment']['proportion'] = (float) $shipment / 100;
    }
    
    if ($values['gc_end_type'] == 'count') {
      $gc['gc_end_type'] = 'count';
      $gc['gc_count'] = $values['gc_count'];
      $gc['gc_count_remaining'] = $values['gc_count_remaining'];
    }
    elseif ($values['gc_end_type'] == 'fixed') {
      $gc['gc_end_type'] = 'fixed';
      $gc['gc_end_date'] = $values['gc_end_date'];
      $gc['gc_end_time'] = strtotime('midnight +1 day', strtotime($values['gc_end_date'])); 
    }
    else {
      $gc['gc_end_type'] = 'none';
    }
    
    $this->item->setData('gc', $gc);
    $this->item->save();
    $form_state->setRedirect('commerce_gc_client.mandate', ['commerce_order' => $this->orderId], ['query' => [
      'item_id' => $this->itemId,
      'action' => 'payment_update',
    ]]);
    $this->messenger()->addMessage($this->t('Scheduled Payments Creation has been updated'));
  }

  /**
   * Update Recurring Order subform.
   *
   * @param array $form
   *   The form.
   * @param object $form_state
   *   The form_state object.
   * @param array $data
   *   Array of module specific data for order item.
   * 
   * @return void
   */
  private function recurringSubform(&$form, $form_state, $data) {
    $form['recurring'] = [
      '#type' => 'details',
      '#title' => $this->t('Update recurring order creation'),
      '#open' => $this->currentRequest->query->get('action') == 'recurring_update',
    ];
    $form['recurring']['create_order'] = [
      '#type' => 'checkbox',
      '#title' => $this->t("Create a recurring order upon creation of recurring payment?"),
      '#default_value' => isset($data['gc_create_order']) ? $data['gc_create_order'] : FALSE,
    ];
    $form['recurring']['email_invoice'] = [
      '#type' => 'checkbox',
      '#title' => $this->t("Email the user an invoice upon creation of a recurring order?"),
      '#default_value' => isset($data['gc_email_invoice']) ? $data['gc_email_invoice'] : FALSE,
      '#states' => [
        'visible' => [
          ':input[id="edit-create-order"]' => [
            'checked' => TRUE,
          ],
        ],
      ],
    ];
    $form['recurring']['recurring_button'] = [
      '#type' => 'submit',
      '#value' => 'Update recurring order creation',
      '#submit' => [[$this, 'recurringUpdateSubmit']],
    ];
  }

  /**
   * Update Recurring Order form submission.
   */
  public function recurringUpdateSubmit(array &$form, FormStateInterface $form_state) {
    $gc = $this->item->getData('gc');
    if ($create_order = $form_state->getValue('create_order')) {
      $gc['gc_create_order'] = TRUE;  
      if ($email_invoice = $form_state->getValue('email_invoice')) {
        $gc['gc_email_invoice'] = TRUE;  
      }
      else {
        $gc['gc_email_invoice'] = FALSE;  
      }
    }
    else {
      $gc['gc_create_order'] = FALSE;  
      $gc['gc_email_invoice'] = FALSE;  
    }
    $this->item->setData('gc', $gc);
    $this->item->save();
    $form_state->setRedirect('commerce_gc_client.mandate', ['commerce_order' => $this->orderId], ['query' => [
      'item_id' => $this->itemId,
      'action' => 'recurring_update',
    ]]);
    $this->messenger()->addMessage($this->t('Recurring Orders Creation has been updated'));
  }

  /**
   * Scheduled adjustments subform.
   *
   * @param array $form
   *   The form.
   * @param object $form_state
   *   The form_state object.
   * @param string $currency_symbol
   *   The relevant currency symbol for the mandate.
   * 
   * @return void
   */
  private function scheduledAdjustmentsSubform(&$form, $form_state, $currency_symbol) {
    $query = $this->db->select('commerce_gc_client_item', 'i');
    $query->join('commerce_gc_client_item_schedule', 's', 's.item_id=i.item_id');
    $adjustments = $query->fields('s')->condition('i.item_id', $this->gc->item_id)->condition('s.type', 'adj')->orderBy('timestamp', 'ASC')->execute()->fetchAll();

    if (!empty($adjustments)) {
      $adj_headers = [
        $this->t('Title'),
        $this->t('Adjustment'),
        $this->t('Date'),
        $this->t('Status'),
        '',
      ];
      $adj_rows = [];
      foreach ($adjustments as $adj) {
        $actions = '';
        if ($adj->status == 1) {
          $actions = $this->t('<a href="@cancel_path">Cancel</a> @spacer', [
            '@cancel_path' => '/gc_client/adjustment_action/cancel/' . $this->orderId . '/' . $adj->sid,
            '@spacer' => '| ',
          ]);
        }
        $actions .= $this->t('<a href="@delete_path">Delete</a>', [
          '@delete_path' => '/gc_client/adjustment_action/delete/' . $this->orderId . '/' . $adj->sid,
        ]);

        if ($adj->status == 0) {
          $status = $this->t('Cancelled');
        }
        elseif ($adj->status == 1) {
          $status = $this->t('Pending');
        }
        elseif ($adj->status == 2) {
          $status = $this->t('Complete');
        }

        $adj_data = unserialize($adj->data);
        $adj_rows[] = [
          $adj_data['title'],
          $this->currencyFormatter->format($adj_data['amount'], $this->commerceCurrencyCode),
          $adj->date,
          $status,
          new FormattableMarkup($actions, []),
        ];
      }
    }
    $form['adjust'] = [
      '#type' => 'details',
      '#title' => $this->t('Schedule adjustments'),
      '#description' => $this->t("Adjust the amount of scheduled payment creations for item."),
      '#open' => $this->currentRequest->query->get('action') == 'adjustment_submit',
    ];
    if ($this->gc->gc_mandate_status == 'cancelled' && !isset($adj_rows)) {
      $form['adjust']['#access'] = FALSE;
    }
    if (isset($adj_rows)) {
      $form['adjust']['adjust_table'] = [
        '#type' => 'details',
        '#title' => $this->t('Adjustments'),
        '#open' => isset($_GET['adjustment']) ? TRUE : FALSE,
      ];
      $form['adjust']['adjust_table']['table'] = [
        '#type' => 'table',
        '#header' => $adj_headers,
        '#rows' => isset($adj_rows) ? $adj_rows : NULL,
      ];
    }
    if ($this->gc->gc_mandate_status != 'cancelled') {
      $form['adjust']['adjust_title'] = [
        '#type' => 'textfield',
        '#size' => 24,
        '#title' => $this->t('Adjustment title'),
        '#default_value' => $this->t('Adjustment for @default_name', [
          '@default_name' => $this->defaultName,
        ]),
      ];
      $form['adjust']['adjustment'] = [
        '#title' => $this->t('Adjustment amount') . ' ' . $currency_symbol,
        '#size' => 10,
        '#type' => 'number',
        '#step' => .01,
        '#default_value' => 0,
        '#description' => $this->t('This will adjust the amount of a payment created with GoCardless.'),
      ];
      $form['adjust']['payments'] = [
        '#type' => 'number',
        '#size' => 6,
        '#title' => $this->t('Number of payments'),
        '#default_value' => 1,
        '#min' => 1,
      ];
      $form['adjust']['starting_radio'] = [
        '#type' => 'radios',
        '#title' => $this->t('Starting from'),
        '#options' => [
          0 => $this->t('Next scheduled payment creation day'),
          1 => $this->t('Select another date'),
        ],
        '#default_value' => 0,
      ];
      $form['adjust']['starting'] = [
        '#type' => 'date',
        '#title' => $this->t('Starting from'),
        '#description' => $this->t('The adjustment will begin on the first scheduled billing date after that specified here.'),
        '#states' => [
          'visible' => [
            ':input[name="starting_radio"]' => [
              'value' => 1,
            ],
          ],
        ],
      ];
      $form['adjust']['plus'] = [
        '#type' => 'details',
        '#title' => $this->t('and then'),
        '#open' => FALSE,
        '#description' => $this->t("Additional scheduled adjustment(s) to follow initial adjustment(s)."),
      ];
      $form['adjust']['plus']['plus_adjustment'] = [
        '#title' => $this->t('Adjustment amount') . ' ' . $currency_symbol,
        '#size' => 10,
        '#type' => 'number',
        '#step' => .01,
      ];
      $form['adjust']['plus']['plus_payments'] = [
        '#type' => 'number',
        '#size' => 6,
        '#title' => $this->t('Number of payments'),
        '#default_value' => NULL,
        '#min' => 1,
      ];
      $form['adjust']['adjust_button'] = [
        '#type' => 'submit',
        '#value' => 'Schedule',
        '#validate' => [[$this, 'adjustmentValidate']],
        '#submit' => [[$this, 'adjustmentSubmit']],
      ];
    }
  }

  /**
   * Scheduled Adjustment validation.
   */
  public function adjustmentValidate(array &$form, FormStateInterface $form_state) {
    $adj = $form_state->getValue('adjustment');
    $plus_adj = $form_state->getValue('plus_adjustment');

    if ($adj == '' || $adj == '0') {
      $form_state->setErrorByName('adjustment', $this->t("You must provide an adjustment value."));
    }

    if ($plus_adj == '0') {
      $form_state->setErrorByName('plus_adjustment', $this->t("Adjustment value cannot be set to zero."));
    }

    if (empty($form_state->getValue('payments'))) {
      $form_state->setValue('payments', 1);
    }

    if (!empty($plus_adj) && empty($form_state->getValue('plus_payments'))) {
      $form_state->setValue('plus_payments', 1);
    }
  }

  /**
   * Scheduled Adjustment submission.
   */
  public function adjustmentSubmit(array &$form, FormStateInterface $form_state) {
    $ints = $this->item->getData('gc')['interval_params'];
    $unit_price = $this->item->getUnitPrice()->getNumber();
    $unit_currency_code = $this->item->getUnitPrice()->getCurrencyCode();

    $query = $this->db->select('commerce_gc_client', 'g');
    $query->join('commerce_gc_client_item', 'i', 'g.gcid=i.gcid');
    $starting = $query->fields('i', ['next_payment'])->condition('item_id', $this->itemId)->execute()->fetchField();

    if ($form_state->getValue('starting_radio') == '1') {
      $select_date = strtotime($form_state->getValue('starting'));
      while ($starting < $select_date) {
        $string_ = '+' . $ints['string'];
        $starting = strtotime($string_, $starting);
      }
    }

    // Create array containing scheduled dates.
    $inserts = [];
    $payments = $form_state->getValue('payments');
    $amount = $form_state->getValue('adjustment');
    for ($i = 0; $i < $payments; $i++) {
      $string_ = '+' . ($i * $ints['length']) . ' ' . str_replace('ly', '', $ints['unit']);
      $inserts[] = [
        'timestamp' => strtotime($string_, $starting),
        'amount' => $amount,
      ];
      $ending = strtotime($string_, $starting);
    }

    if (!empty($form_state->getValue('plus_adjustment'))) {
      // Create array containing additional scheduled dates.
      $plus_amount = $form_state->getValue('plus_adjustment');
      $plus_starting = strtotime('+' . $ints['string'], $ending);
      $plus_payments = $form_state->getvalue('plus_payments');
      for ($i = 0; $i < $plus_payments; $i++) {
        $string_ = '+' . ($i * $ints['length']) . ' ' . str_replace('ly', '', $ints['unit']);
        $inserts[] = [
          'timestamp' => strtotime($string_, $plus_starting),
          'amount' => $plus_amount,
        ];
      }
    }

    // Add schedules data to database.
    foreach ($inserts as $insert) {
      // Check validity of new scheduled adjustments and disallow if it will
      // cause a payment creation of less than one and not zero.
      $insert_date = date('d M Y', $insert['timestamp']);

      // Calculate sum of scheduled adjs for date.
      $query = $this->db->select('commerce_gc_client_item', 'i');
      $query->join('commerce_gc_client_item_schedule', 's', 'i.item_id = s.item_id');
      $scheds = $query->fields('s')
        ->condition('s.type', 'adj')
        ->condition('s.status', 1)
        ->condition('s.date', $insert_date)
        ->condition('i.item_id', $this->itemId)
        ->execute()
        ->fetchAll();

      $sum = 0;
      foreach ($scheds as $sched) {
        $sched_data = unserialize($sched->data);
        $sum = $sum + $sched_data['amount'];
      }
      $sum = ($sum + $insert['amount'] + $unit_price);

      if ($sum < 1 && $sum != 0) {
        $this->messenger()->addWarning($this->t('The schedule adjustment for @date cannot be placed because the price of the item inluding adjustments is not zero, and is less than @amount, which is not allowed by GoCardless.', [
          '@date' => $insert_date,
          '@amount' => $this->currencyFormatter->format(1, $unit_currency_code),
        ]));
        continue;
      }

      $insert_date = date('d M Y', $insert['timestamp']);
      $this->db->insert('commerce_gc_client_item_schedule')->fields([
        'item_id' => $this->itemId,
        'type' => 'adj',
        'date' => $insert_date,
        'timestamp' => strtotime($insert_date),
        'status' => 1,
        'data' => serialize([
          'title' => !empty($form_state->getValue('adjust_title')) ? $form_state->getValue('adjust_title') : $this->t('Adjustment'),
          'amount' => $insert['amount'],
        ]),
        'created' => $this->time->getRequestTime(),
      ])->execute();

      $this->messenger()->addMessage($this->t('Schedule adjustment created for @date.', [
        '@date' => $insert_date,
      ]));
    }

    $form_state->setRedirect('commerce_gc_client.mandate', ['commerce_order' => $this->orderId], ['query' => [
      'action' => 'adjustment_submit',
      'item_id' => $this->itemId,
    ]]);
  }

  /**
   * AJAX callback function.
   *
   * Reloads the form.
   */
  public static function switchItem(array &$form, FormStateInterface $form_state) {
    $item_id = $form_state->getValue('item_id');
    $order_id = $form_state->getValue('order_id');
    $path = '/admin/commerce/orders/' . $order_id . '/gocardless?item_id=' . $item_id;
    $response = new AjaxResponse();
    $response->addCommand(new RedirectCommand($path));
    return $response;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc