You are here

public function Square::createPayment in Commerce Square Connect 8

Creates a payment.

Parameters

\Drupal\commerce_payment\Entity\PaymentInterface $payment: The payment.

bool $capture: Whether the created payment should be captured (VS authorized only). Allowed to be FALSE only if the plugin supports authorizations.

Throws

\InvalidArgumentException If $capture is FALSE but the plugin does not support authorizations.

\Drupal\commerce_payment\Exception\PaymentGatewayException Thrown when the transaction fails for any reason.

Overrides SupportsStoredPaymentMethodsInterface::createPayment

File

src/Plugin/Commerce/PaymentGateway/Square.php, line 179

Class

Square
Provides the Square payment gateway.

Namespace

Drupal\commerce_square\Plugin\Commerce\PaymentGateway

Code

public function createPayment(PaymentInterface $payment, $capture = TRUE) {
  $this
    ->assertPaymentState($payment, [
    'new',
  ]);
  $payment_method = $payment
    ->getPaymentMethod();
  $this
    ->assertPaymentMethod($payment_method);
  $paid_amount = $payment
    ->getAmount();
  $rounder = \Drupal::getContainer()
    ->get('commerce_price.rounder');

  /** @var \Drupal\commerce_price\Price $paid_amount */
  $paid_amount = $rounder
    ->round($paid_amount);
  $currency = $paid_amount
    ->getCurrencyCode();

  // Square only accepts integers and not floats.
  // @see https://docs.connect.squareup.com/api/connect/v2/#workingwithmonetaryamounts
  $square_total_amount = $this
    ->toMinorUnits($paid_amount);
  $billing = $payment_method
    ->getBillingProfile();

  /** @var \Drupal\address\Plugin\Field\FieldType\AddressItem $address */
  $address = $billing
    ->get('address')
    ->first();
  $mode = $this
    ->getMode();
  $order = new Order();
  $order
    ->setReferenceId($payment
    ->getOrderId());
  $order
    ->setLocationId($this->configuration[$mode . '_location_id']);
  $line_items = [];
  $line_item_total = 0;
  foreach ($payment
    ->getOrder()
    ->getItems() as $item) {
    $line_item = new OrderLineItem();
    $base_price_money = new Money();
    $square_amount = $this
      ->toMinorUnits($rounder
      ->round($item
      ->getUnitPrice()));
    $base_price_money
      ->setAmount($square_amount);
    $base_price_money
      ->setCurrency($currency);
    $line_item
      ->setBasePriceMoney($base_price_money);
    $square_amount = $this
      ->toMinorUnits($rounder
      ->round($item
      ->getTotalPrice()));
    $line_item
      ->setName($item
      ->getTitle());

    // Quantity needs to be a string integer.
    $line_item
      ->setQuantity((string) (int) $item
      ->getQuantity());
    $line_item_total += $square_amount;
    $line_items[] = $line_item;
  }

  // Square requires the order total to match the payment amount.
  if ($line_item_total != $square_total_amount) {
    $diff = $square_total_amount - $line_item_total;
    if ($diff < 0) {
      $discount_money = new Money();
      $discount_money
        ->setCurrency($currency);
      $discount_money
        ->setAmount(-$diff);
      $discount = new CreateOrderRequestDiscount();
      $discount
        ->setAmountMoney($discount_money);
      $discount
        ->setName('Adjustments');
    }
    else {
      $line_item = new OrderLineItem();
      $total_money = new Money();
      $total_money
        ->setAmount((int) $diff);
      $total_money
        ->setCurrency($currency);
      $line_item
        ->setBasePriceMoney($total_money);
      $line_item
        ->setName('Adjustments');
      $line_item
        ->setQuantity("1");
      $line_items[] = $line_item;
    }
  }
  $order
    ->setLineItems($line_items);
  if (isset($discount)) {
    $order
      ->setDiscounts([
      $discount,
    ]);
  }

  // @todo integration_id is not supported by the SDK.
  // @see https://github.com/square/connect-php-sdk/issues/94
  $charge_request = new IntegrationChargeRequest();
  $charge_request
    ->setAmountMoney(new Money([
    'amount' => $square_total_amount,
    'currency' => $currency,
  ]));
  if ($mode === 'live') {
    $charge_request
      ->setIntegrationId('sqi_b6ff0cd7acc14f7ab24200041d066ba6');
  }
  $charge_request
    ->setDelayCapture(!$capture);
  $charge_request
    ->setCardNonce($payment_method
    ->getRemoteId());
  $charge_request
    ->setIdempotencyKey(uniqid('', TRUE));
  $charge_request
    ->setBuyerEmailAddress($payment
    ->getOrder()
    ->getEmail());
  $charge_request
    ->setBillingAddress(new Address([
    'address_line_1' => $address
      ->getAddressLine1(),
    'address_line_2' => $address
      ->getAddressLine2(),
    'locality' => $address
      ->getLocality(),
    'sublocality' => $address
      ->getDependentLocality(),
    'administrative_district_level_1' => $address
      ->getAdministrativeArea(),
    'postal_code' => $address
      ->getPostalCode(),
    'country' => $address
      ->getCountryCode(),
    'first_name' => $address
      ->getGivenName(),
    'last_name' => $address
      ->getFamilyName(),
    'organization' => $address
      ->getOrganization(),
  ]));
  try {
    $api_client = $this
      ->getApiClient();

    // Create order.
    $order_request = new CreateOrderRequest();
    $order_request
      ->setIdempotencyKey(uniqid($payment
      ->getOrderId() . '-', TRUE));
    $order_request
      ->setOrder($order);
    $orders_api = new OrdersApi($api_client);
    $result = $orders_api
      ->createOrder($this->configuration[$mode . '_location_id'], $order_request);
    $charge_request
      ->setOrderId($result
      ->getOrder()
      ->getId());
    $transactions_api = new TransactionsApi($api_client);
    $result = $transactions_api
      ->charge($this->configuration[$mode . '_location_id'], $charge_request);
  } catch (ApiException $e) {
    throw ErrorHelper::convertException($e);
  }
  $transaction = $result
    ->getTransaction();
  $tender = $transaction
    ->getTenders()[0];
  $next_state = $capture ? 'completed' : 'authorization';
  $payment
    ->setState($next_state);
  $payment
    ->setRemoteId($transaction
    ->getId() . '|' . $tender
    ->getId());
  $payment
    ->setAuthorizedTime($transaction
    ->getCreatedAt());
  if ($capture) {
    $payment
      ->setCompletedTime($result
      ->getTransaction()
      ->getCreatedAt());
  }
  else {
    $expires = $this->time
      ->getRequestTime() + 3600 * 24 * 6 - 5;
    $payment
      ->setExpiresTime($expires);
  }
  $payment
    ->save();
}