uc_gc_client-8.x-1.x-dev/src/Controller/GoCardless.php

src/Controller/GoCardless.php
<?php

namespace Drupal\uc_gc_client\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\uc_gc_client\Plugin\Ubercart\PaymentMethod\GoCardlessClient;
use Drupal\uc_order\Entity\Order;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Component\Uuid\Php;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\uc_payment\Plugin\PaymentMethodManager;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Datetime\DateFormatterInterface;
use Drupal\user\PrivateTempStoreFactory;

/**
 * Returns responses for GoCardless routes.
 */
class GoCardless extends ControllerBase {

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

  /**
   * The uc_store configuration settings.
   *
   * @var array
   */
  protected $ucStoreSettings;

  /**
   * The Ubercart payment method manager.
   *
   * @var \Drupal\uc_payment\Plugin\PaymentMethodManager
   */
  protected $ucPaymentMethod;

  /**
   * The module handler.
   *
   * @var \Drupal\core\extension\modulehandler
   */
  protected $moduleHandler;

  /**
   * The Private Tempstore Factory.
   *
   * @var \Drupal\user\PrivateTempStoreFactory
   */
  protected $tempStore;

  /**
   * The Uuid service.
   *
   * @var \Drupal\Component\Uuid\Php;
   */
  protected $uuidService;

  /**
   * Constructs the GoCardless object.
   *
   * @param \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter
   *   The date formatter.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The Config Factory interface.
   * @param \Drupal\uc_payment\Plugin\PaymentMethodManager $ucPaymentMethod
   *   The Ubercart payment method manager.
   * @param \Drupal\Core\Extension\ModuleHandler $moduleHandler
   *   The module handler.
   * @param \Drupal\user\PrivateTempStoreFactory $tempStoreFactory
   *   The Private Tempstore Factory.
   * @param \Drupal\Component\Uuid\Pho $uuidService
   *   The Uuid PHP service.
   */
  public function __construct(DateFormatterInterface $dateFormatter, ConfigFactoryInterface $configFactory, PaymentMethodManager $ucPaymentMethod, ModuleHandler $moduleHandler, PrivateTempStoreFactory $tempStoreFactory, Php $uuidService) {
    $this->dateFormatter = $dateFormatter;
    $this->ucStoreSettings = $configFactory->get('uc_store.settings')->get();
    $this->ucPaymentMethod = $ucPaymentMethod;
    $this->moduleHandler = $moduleHandler;
    $this->tempStore = $tempStoreFactory->get('uc_gc_client');
    $this->uuidService = $uuidService;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('date.formatter'),
      $container->get('config.factory'),
      $container->get('plugin.manager.uc_payment.method'),
      $container->get('module_handler'),
      $container->get('user.private_tempstore'),
      $container->get('uuid')
    );
  }

  /**
   * Handles a complete GoCardless order.
   *
   * @return \Symfony\Component\HttpFoundation\RedirectResponse
   *   A redirect to the cart or checkout complete page.
   */
  public function goCardlessComplete($redirect, $mandate_id, $customer, $order_id, $start_date = NULL, $cart_id = 0) {

    // Obtain mandate object from GoCardless to check it is valid, and to
    // get the currency scheme.
    $partner = new GoCardlessPartner();
    $result = $partner->api([
      'endpoint' => 'mandates',
      'action' => 'get',
      'mandate' => $mandate_id,
    ]);
    if ($result->response->status_code != 200) {
      return $this->redirect('uc_cart.cart');
    }
    else {
      $mandate = $result->response->body->mandates;
    }

    // Ensure the payment method is GoCardless.
    $order = Order::load($order_id);
    $method = $this->ucPaymentMethod->createFromOrder($order);
    if (!$method instanceof GoCardlessClient) {
      return $this->redirect('uc_cart.cart');
    }

    $uid = $order->getOwnerId();

    // Let customer know mandate has been created.
    $comment = $this->t('Your new direct debit mandate @mandate has been created by GoCardless.', [
      '@mandate' => $mandate_id,
    ]);
    uc_order_comment_save($order_id, $uid, $comment, 'order', 'pending', TRUE);
    drupal_set_message($comment);

    // Set up seperate payments / subscriptions for each product in cart.
    foreach ($order->products as $product) {
      $uuid = $this->uuidService->generate();
      $ucpid = $product->order_product_id->value;
      $data = $product->data->getValue()[0];
      //If the payment type isn't set then set it to 'P' by default.
      $gc_type = isset($data['gc_auth_type']) && $data['gc_auth_type'] == 'subscription' ? 'S' : 'P';
      $product_uc = db_select('uc_gc_client_products', 'p')
        ->fields('p')
        ->condition('nid', $product->nid->getString())
        ->execute()->fetch();

      // Obtain initial payment creation date.
      // Use start date.
      if ($product_uc->start_date) {
        if (strtotime($product_uc->start_date) < REQUEST_TIME) {
          $start_date = REQUEST_TIME;
        }
        else {
          $start_date = strtotime($product_uc->start_date);
        }
      }

      // Use day(s) of month.
      elseif ($product_uc->dom) {
        $doms = explode(',', $product_uc->dom);
        $dates = [];
        foreach ($doms as $dom) {
          $dom >= date('d') ? $month = 'last' : $month = 'this';
          $time = strtotime('+' . $dom . ' days', strtotime('last day of ' . $month . ' month'));
          $dates[] = $time;
        }
        sort($dates);
        $start_date = array_shift($dates);
      }

      // Create payment immidiately.
      elseif ($product_uc->create_payment) {
        $start_date = REQUEST_TIME;
      }

      // Provide hook so initial date can be provided by another module.
      elseif (is_null($start_date)) {
        $this->moduleHandler->alter('gc_client_start_date', $start_date, $product);
      }

      // Insert info about the order into the database.
      $created = REQUEST_TIME;
      $insert_fields = [
        'ucid'   => $order_id,
        'ucpid'  => $ucpid,
        'gcid'   => $mandate_id,
        'gcrid'  => $redirect,
        'gccid'  => $customer,
        'scheme' => $mandate->scheme,
        'uid'    => $uid,
        'type'   => $gc_type,
        'status' => 'pending_submission',
        'created' => $created,
        'start_date' => $start_date,
        'updated' => $created,
        'sandbox' =>  \Drupal::config('uc_gc_client.settings')->get('sandbox'),
      ];
      $update_fields = [
        'updated' => $created,
      ];
      db_merge('uc_gc_client')
        ->key(['ucpid' => $ucpid])
        ->insertFields($insert_fields)
        ->updateFields($update_fields)
        ->execute();

      isset($data['interval_params']) ? $interval = $data['interval_params'] : NULL;
      $currency_code = $this->ucStoreSettings['currency']['code'];
      $currency_sign = $this->ucStoreSettings['currency']['symbol'];

      // Subscription payments.
      if ($gc_type == 'S') {
        $calculate = uc_gc_client_price_calculate($order, $ucpid);
        if (isset($calculate['currency'])) {
          $currency_code = $calculate['currency'];
        }
        if (isset($calculate['sign'])) {
          $currency_sign = $calculate['sign'];
        }

        $payment_details = [
          'type' => 'subscription',
          'amount' => $calculate['amount'],
          'currency' => $currency_code,
          'name' => 'Subscription plan for ' . $product->title->value,
          'interval' => $interval['length'],
          'interval_unit' => $interval['unit_gc'],
          'metadata' => [
            'ucpid' => $ucpid,
          ],
        ];

        // Provide hook so payment details can be altered by another module
        // before the payment is created with GC.
        $this->moduleHandler->alter('gc_client_subs_payment', $payment_details, $order);

        $params = [
          'endpoint' => 'subscriptions',
          'action' => 'create',
          'mandate' => $mandate_id,
          'amount' => $payment_details['amount'],
          'currency' => $payment_details['currency'],
          'name' => $payment_details['name'],
          'interval' => $payment_details['interval'],
          'interval_unit' => $payment_details['interval_unit'],
          'metadata' => $payment_details['metadata'],
          'idempotency_key' => $uuid,
        ];
        if (!isset($product_uc->create_payment)) {
          $params['start_date'] = $this->dateFormatter->format($start_date, 'gocardless');
        }
        $result = $partner->api($params);

        if ($result->response->status_code == 201) {
          $sub = $result->response->body->subscriptions;
          $comment_arr = [
            '@product' => $product->title->value,
            '@interval' => $sub->interval,
            '@interval_unit' => $sub->interval_unit,
            '@amount' => uc_currency_format($sub->amount / 100, $currency_sign),
            '@start_date' => $this->dateFormatter->format(strtotime($sub->start_date), 'uc_store'),
          ];
          $comment = $this->t('Your @interval @interval_unit subscription plan of @amount for @product has been created with GoCardless, and the first payment will be made from your bank on @start_date.', $comment_arr);
          uc_order_comment_save($order_id, $uid, $comment, 'order', 'pending', TRUE);
          drupal_set_message($comment);
        }
        else {
          if (!isset($result->response) || !$result->response || $result->response->status_code == 500) {
            drupal_set_message($this->t('There was a problem creating your subscription at GoCardless, so we will resubmit it later.'), 'warning');
            db_update('uc_gc_client')->fields([
              'next_payment' => $created,
              'next_payment_uuid' => $uuid,
            ])->condition('ucpid', $ucpid)->execute();
            $data['subscription_details'] = $params;
            $product->set('data', $data)->save();
          }
          else {
            drupal_set_message($this->t('Something went wrong creating your subscription with GoCardless. Please contact the site administrator for assistance.'), 'error');
          }
        }
      }

      // One-off payments.
      elseif ($gc_type == 'P') {
        // Create the first payment immediately.
        if (!is_null($start_date) && $start_date <= REQUEST_TIME) {
          $calculate = uc_gc_client_price_calculate($order, $ucpid);
          if (isset($calculate['currency'])) {
            $currency_code = $calculate['currency'];
          }
          if (isset($calculate['sign'])) {
            $currency_sign = $calculate['sign'];
          }
          $order->save();
          $payment_details = [
            'type' => 'one-off payment',
            'amount' => $calculate['amount'],
            'currency' => $currency_code,
            'description' => 'Initial payment for ' . $product->title->value,
            'metadata' => [
              'ucpid' => $ucpid,
            ],
          ];

          // Provide hook so payment details can be altered by another module
          // before the payment is created with GC.
          $this->moduleHandler->alter('gc_client_payments_payment', $payment_details, $order);

          $result = $partner->api([
            'endpoint' => 'payments',
            'action' => 'create',
            'mandate' => $mandate_id,
            'amount' => $payment_details['amount'],
            'currency' => $payment_details['currency'],
            'description' => $payment_details['description'],
            'metadata' => $payment_details['metadata'],
            'idempotency_key' => $uuid,
          ]);
 
          if ($result->response->status_code == 201) {
            // Update next_payment field in gc_client table.
            $payment = $result->response->body->payments;
            isset($interval) ? $next_payment = strtotime('+' . $interval['string']) : $next_payment = NULL;
            db_update('uc_gc_client')
              ->fields([
                'next_payment' => $next_payment,
              ])
              ->condition('ucpid', $ucpid)
              ->execute();

            // Let everyone know what is going on.
            $comment_array = [
              '@amount' => uc_currency_format($payment->amount / 100, $currency_sign),
              '@charge_date' => date('D d M Y', strtotime($result->response->body->payments->charge_date)),
              '@product' => $product->title->value,
            ];
            $comment = $this->t('An initial payment of @amount for @product has been created with GoCardless, and will be made from your bank on @charge_date.', $comment_array);
            uc_order_comment_save($order_id, $uid, $comment, 'order', 'pending', TRUE);
            drupal_set_message($comment);
          }

          else {
            drupal_set_message($this->t('An initial payment could not be created due to an unknown error. We will try and raise it again later.'), 'warning');

            // Update next_payment to created time so that it will get picked
            // up on next cron run.
            $update = [
              'next_payment' => $created,
            ];
            if (!isset($result->response) || !$result->response || $result->response->status_code == 500) {
              // Provide the next payment with the Uuid which will be re-
              // submitted in the cron run to ensure a duplicate payment isn't
              // created.
              $update['next_payment_uuid'] = $uuid;
            }
            
            db_update('uc_gc_client')
              ->fields($update)->condition('ucpid', $ucpid)->execute();
          }
        }

        // Else if a start date is set for the product then defer the
        // first payment creation.
        elseif (!is_null($start_date)) {
          // Update next_payment field in uc_gcsubs table.
          db_update('uc_gc_client')
            ->fields([
              'next_payment' => $start_date,
              'updated' => REQUEST_TIME,
            ])
            ->condition('ucpid', $ucpid)
            ->execute();

          $calculate = uc_gc_client_price_calculate($order, $ucpid);
          if (isset($calculate['currency'])) {
            $currency_code = $calculate['currency'];
          }
          if (isset($calculate['sign'])) {
            $currency_sign = $calculate['sign'];
          }
          $order->save();

          // Let everyone know what is going on.
          $comment = $this->t('A payment for @amount will be created with GoCardless on @start_date.', [
            '@amount' => uc_currency_format($calculate['amount'], $currency_sign),
            '@start_date' => $this->dateFormatter->format($start_date, 'uc_store'),
          ]);
          uc_order_comment_save($order_id, $uid, $comment, 'order', 'pending', TRUE);
          drupal_set_message($comment);
        }
      }
    }

    // This lets us know it's a legitimate access of the complete page.
    // $this->tempStore->set('uc_checkout_complete_' . $order_id, TRUE);.
    $session = \Drupal::service('session');
    $session->remove('uc_checkout_review_' . $order->id());
    $session->set('uc_checkout_complete_' . $order_id, TRUE);

    return $this->redirect('uc_cart.checkout_complete');
  }

}

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

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