View source
<?php
namespace Drupal\commerce_authnet\Plugin\Commerce\PaymentGateway;
use CommerceGuys\AuthNet\DataTypes\Shipping;
use Drupal\commerce_order\AdjustmentTransformerInterface;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_payment\Entity\PaymentInterface;
use Drupal\commerce_payment\Entity\PaymentMethodInterface;
use Drupal\commerce_payment\Exception\InvalidResponseException;
use Drupal\commerce_payment\Exception\PaymentGatewayException;
use Drupal\commerce_payment\PaymentMethodTypeManager;
use Drupal\commerce_payment\PaymentTypeManager;
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OnsitePaymentGatewayBase;
use Drupal\commerce_price\Calculator;
use Drupal\commerce_price\MinorUnitsConverterInterface;
use Drupal\commerce_price\Price;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url;
use GuzzleHttp\ClientInterface;
use CommerceGuys\AuthNet\Configuration;
use CommerceGuys\AuthNet\CreateTransactionRequest;
use CommerceGuys\AuthNet\DataTypes\LineItem;
use CommerceGuys\AuthNet\DataTypes\MerchantAuthentication;
use CommerceGuys\AuthNet\DataTypes\TransactionRequest;
use CommerceGuys\AuthNet\DeleteCustomerPaymentProfileRequest;
use CommerceGuys\AuthNet\Request\XmlRequest;
use CommerceGuys\AuthNet\Response\ResponseInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OnsitePaymentGatewayInterface;
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\SupportsAuthorizationsInterface;
use CommerceGuys\AuthNet\DataTypes\Tax;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
abstract class OnsiteBase extends OnsitePaymentGatewayBase implements OnsitePaymentGatewayInterface, SupportsAuthorizationsInterface {
protected $adjustmentTransformer;
protected $authnetConfiguration;
protected $httpClient;
protected $logger;
protected $privateTempStore;
protected $messenger;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, MinorUnitsConverterInterface $minor_units_converter, ClientInterface $client, LoggerInterface $logger, PrivateTempStoreFactory $private_tempstore, AdjustmentTransformerInterface $adjustment_transformer, MessengerInterface $messenger) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $payment_type_manager, $payment_method_type_manager, $time, $minor_units_converter);
$this->httpClient = $client;
$this->logger = $logger;
$this->authnetConfiguration = new Configuration([
'sandbox' => $this
->getMode() == 'test',
'api_login' => $this->configuration['api_login'],
'transaction_key' => $this->configuration['transaction_key'],
'client_key' => $this->configuration['client_key'],
]);
$this->privateTempStore = $private_tempstore;
$this->adjustmentTransformer = $adjustment_transformer;
$this->messenger = $messenger;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('plugin.manager.commerce_payment_type'), $container
->get('plugin.manager.commerce_payment_method_type'), $container
->get('datetime.time'), $container
->get('commerce_price.minor_units_converter'), $container
->get('http_client'), $container
->get('commerce_authnet.logger'), $container
->get('tempstore.private'), $container
->get('commerce_order.adjustment_transformer'), $container
->get('messenger'));
}
public function defaultConfiguration() {
return [
'api_login' => '',
'transaction_key' => '',
'client_key' => '',
] + parent::defaultConfiguration();
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['api_login'] = [
'#type' => 'textfield',
'#title' => $this
->t('Login ID'),
'#default_value' => $this->configuration['api_login'],
'#required' => TRUE,
];
$form['transaction_key'] = [
'#type' => 'textfield',
'#title' => $this
->t('Transaction Key'),
'#default_value' => $this->configuration['transaction_key'],
'#required' => TRUE,
];
$form['client_key'] = [
'#type' => 'textfield',
'#title' => $this
->t('Client Key'),
'#description' => $this
->t('Follow the instructions <a href="https://developer.authorize.net/api/reference/features/acceptjs.html#Obtaining_a_Public_Client_Key">here</a> to get a client key.'),
'#default_value' => $this->configuration['client_key'],
'#required' => TRUE,
];
try {
$url = Url::fromRoute('entity.commerce_checkout_flow.collection');
$form['transaction_type'] = [
'#markup' => $this
->t('<p>To configure the transaction settings, modify the <em>Payment process</em> pane in your checkout flow. From there you can choose authorization only or authorization and capture. You can manage your checkout flows here: <a href=":url">:url</a></p>', [
':url' => $url
->toString(),
]) . $this
->t('<p>For Echeck to work Transaction Details API needs to be enabled in your merchant account ("Account" => "Transaction Details API").</p>'),
];
} catch (\Exception $e) {
}
return $form;
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state);
$values = $form_state
->getValue($form['#parents']);
if (!empty($values['api_login']) && !empty($values['transaction_key'])) {
$request = new XmlRequest(new Configuration([
'sandbox' => $values['mode'] == 'test',
'api_login' => $values['api_login'],
'transaction_key' => $values['transaction_key'],
]), $this->httpClient, 'authenticateTestRequest');
$request
->addDataType(new MerchantAuthentication([
'name' => $values['api_login'],
'transactionKey' => $values['transaction_key'],
]));
$response = $request
->sendRequest();
if ($response
->getResultCode() != 'Ok') {
$this
->logResponse($response);
$this->messenger
->addError($this
->describeResponse($response));
}
}
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
if (!$form_state
->getErrors()) {
$values = $form_state
->getValue($form['#parents']);
$this->configuration['api_login'] = $values['api_login'];
$this->configuration['transaction_key'] = $values['transaction_key'];
$this->configuration['client_key'] = $values['client_key'];
}
}
public function capturePayment(PaymentInterface $payment, Price $amount = NULL) {
$this
->assertPaymentState($payment, [
'authorization',
]);
$amount = $amount ?: $payment
->getAmount();
$request = new CreateTransactionRequest($this->authnetConfiguration, $this->httpClient);
$request
->setTransactionRequest(new TransactionRequest([
'transactionType' => TransactionRequest::PRIOR_AUTH_CAPTURE,
'amount' => $amount
->getNumber(),
'refTransId' => $payment
->getRemoteId(),
]));
$response = $request
->execute();
if ($response
->getResultCode() != 'Ok') {
$this
->logResponse($response);
$message = $response
->getMessages()[0];
throw new PaymentGatewayException($message
->getText());
}
$payment
->setState('completed');
$payment
->setAmount($amount);
$payment
->save();
}
public function voidPayment(PaymentInterface $payment) {
$this
->assertPaymentState($payment, [
'authorization',
]);
$request = new CreateTransactionRequest($this->authnetConfiguration, $this->httpClient);
$request
->setTransactionRequest(new TransactionRequest([
'transactionType' => TransactionRequest::VOID,
'amount' => $payment
->getAmount()
->getNumber(),
'refTransId' => $payment
->getRemoteId(),
]));
$response = $request
->execute();
if ($response
->getResultCode() != 'Ok') {
$this
->logResponse($response);
$message = $response
->getMessages()[0];
throw new PaymentGatewayException($message
->getText());
}
$payment
->setState('authorization_voided');
$payment
->save();
}
public function deletePaymentMethod(PaymentMethodInterface $payment_method) {
$owner = $payment_method
->getOwner();
$customer_id = $this
->getRemoteCustomerId($owner);
if (empty($customer_id)) {
$customer_id = $this
->getPaymentMethodCustomerId($payment_method);
}
$request = new DeleteCustomerPaymentProfileRequest($this->authnetConfiguration, $this->httpClient);
$request
->setCustomerProfileId($customer_id);
$request
->setCustomerPaymentProfileId($this
->getRemoteProfileId($payment_method));
$response = $request
->execute();
if ($response
->getResultCode() != 'Ok') {
$this
->logResponse($response);
$message = $response
->getMessages()[0];
if ($message
->getCode() != 'E00040') {
throw new InvalidResponseException("Unable to delete payment method");
}
}
$payment_method
->delete();
}
protected function logResponse(ResponseInterface $response) {
$message = $this
->describeResponse($response);
$level = $response
->getResultCode() === 'Error' ? 'error' : 'info';
$this->logger
->log($level, $message);
}
public function getPaymentMethodCustomerId(PaymentMethodInterface $payment_method) {
$remote_id = $payment_method
->getRemoteId();
if (strstr($remote_id, '|')) {
$ids = explode('|', $remote_id);
return reset($ids);
}
return FALSE;
}
public function getRemoteProfileId(PaymentMethodInterface $payment_method) {
$remote_id = $payment_method
->getRemoteId();
$ids = explode('|', $remote_id);
return end($ids);
}
protected function describeResponse(ResponseInterface $response) {
$messages = [];
foreach ($response
->getMessages() as $message) {
$messages[] = $message
->getCode() . ': ' . $message
->getText();
}
return $this
->t('Received response with code %code from Authorize.net: @messages', [
'%code' => $response
->getResultCode(),
'@messages' => implode("\n", $messages),
]);
}
protected function getLineItems(OrderInterface $order) {
$line_items = [];
foreach ($order
->getItems() as $order_item) {
$name = $order_item
->label();
$name = strlen($name) > 31 ? substr($name, 0, 28) . '...' : $name;
$line_items[] = new LineItem([
'itemId' => $order_item
->id(),
'name' => $name,
'quantity' => $order_item
->getQuantity(),
'unitPrice' => $order_item
->getUnitPrice()
->getNumber(),
]);
}
return $line_items;
}
protected function getTax(OrderInterface $order) {
$amount = '0';
$labels = [];
$adjustments = $order
->collectAdjustments();
if ($adjustments) {
$adjustments = $this->adjustmentTransformer
->combineAdjustments($adjustments);
$adjustments = $this->adjustmentTransformer
->roundAdjustments($adjustments);
foreach ($adjustments as $adjustment) {
if ($adjustment
->getType() !== 'tax') {
continue;
}
$amount = Calculator::add($amount, $adjustment
->getAmount()
->getNumber());
$labels[] = $adjustment
->getLabel();
}
}
$labels = array_unique($labels);
if (empty($labels)) {
$name = '';
$description = '';
}
elseif (count($labels) > 1) {
$name = 'Multiple Tax Types';
$description = implode(', ', $labels);
}
else {
$name = $labels[0];
$description = $labels[0];
}
$name = strlen($name) > 31 ? substr($name, 0, 28) . '...' : $name;
$description = strlen($description) > 255 ? substr($description, 0, 252) . '...' : $description;
if ($amount < 0) {
$amount = 0;
$name = '';
$description = '';
}
return new Tax([
'amount' => $amount,
'name' => $name,
'description' => $description,
]);
}
protected function getShipping(OrderInterface $order) {
if (!$order
->hasField('shipments')) {
return new Shipping([
'amount' => 0,
'name' => '',
'description' => '',
]);
}
$amount = '0';
$labels = [];
$shipments = $order
->get('shipments')
->referencedEntities();
if ($shipments) {
foreach ($shipments as $shipment) {
if ($shipment_amount = $shipment
->getAmount()) {
$amount = Calculator::add($amount, $shipment_amount
->getNumber());
$labels[] = $shipment
->label();
}
}
}
$labels = array_unique($labels);
if (empty($labels)) {
$name = '';
$description = '';
}
elseif (count($labels) > 1) {
$name = 'Multiple shipments';
$description = implode(', ', $labels);
}
else {
$name = $labels[0];
$description = $labels[0];
}
$name = strlen($name) > 31 ? substr($name, 0, 28) . '...' : $name;
$description = strlen($description) > 255 ? substr($description, 0, 252) . '...' : $description;
return new Shipping([
'amount' => $amount,
'name' => $name,
'description' => $description,
]);
}
}