View source
<?php
namespace Drupal\commerce_mollie\Plugin\Commerce\PaymentGateway;
use Drupal;
use Drupal\commerce_mollie\ErrorHelper;
use Drupal\commerce_payment\Entity\PaymentInterface;
use Drupal\commerce_payment\PaymentMethodTypeManager;
use Drupal\commerce_payment\PaymentTypeManager;
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\HasPaymentInstructionsInterface;
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OffsitePaymentGatewayBase;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Mollie\Api\Exceptions\ApiException as MollieApiException;
use Mollie\Api\Types\PaymentStatus as MolliePaymentStatus;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class Mollie extends OffsitePaymentGatewayBase implements HasPaymentInstructionsInterface {
protected $api;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $payment_type_manager, $payment_method_type_manager, $time);
$this->api = Drupal::service('commerce_mollie.mollie.api');
try {
if (!empty($configuration['api_key_live']) && $configuration['api_key_live'] !== $this
->defaultConfiguration()['api_key_live'] && $configuration['mode'] === 'live') {
$this->api
->setApiKey($configuration['api_key_live']);
}
elseif (!empty($configuration['api_key_test']) && $configuration['api_key_test'] !== $this
->defaultConfiguration()['api_key_test'] && $configuration['mode'] === 'test') {
$this->api
->setApiKey($configuration['api_key_test']);
}
} catch (MollieApiException $e) {
ErrorHelper::handleException($e);
}
}
public function defaultConfiguration() {
$default_configuration = [
'api_key_test' => 'test_',
'api_key_live' => 'live_',
'callback_domain' => '',
];
return $default_configuration + parent::defaultConfiguration();
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$order_workflow = Drupal::config('commerce_order.commerce_order_type.default')
->get('workflow');
if (strpos($order_workflow, 'validation') === FALSE) {
$link = Link::fromTextAndUrl($this
->t('Configure Order Types workflow'), Url::fromRoute('entity.commerce_order_type.collection'))
->toString();
Drupal::messenger()
->addWarning($this
->t('It is recommended to configure a workflow with a Validation step. @link', [
'@link' => $link,
]));
}
$host = Drupal::request()
->getHost();
$form['api_key_test'] = [
'#type' => 'textfield',
'#title' => $this
->t('Mollie Test API-key'),
'#default_value' => $this->configuration['api_key_test'],
'#required' => TRUE,
];
$form['api_key_live'] = [
'#type' => 'textfield',
'#title' => $this
->t('Mollie Live API-key'),
'#default_value' => $this->configuration['api_key_live'],
'#required' => TRUE,
];
$form['callback_domain'] = [
'#type' => 'textfield',
'#title' => $this
->t('Callback domain'),
'#description' => $this
->t('Callback domain that Mollie must use to post transaction results to.<br/>
<ul>
<li>Do not add an "/" after .com</li>
<li>You must include https:// or http://</li>
<li>The domain must be reachable for the Mollie servers, otherwise payments are not processed.</li>
</ul>
For live websites this is the your live domain</br><br/>
If left empty the domain visible in the browser window will be used.<br/>
Currently that is: @host<br/><br/>
While developing you can use a tunneled domain that hits your local development machine.<br/>
This can be done with https://localtunnel.github.io/www<br/>
<code>lt --port 80 --local-host @host</code>
', [
'@host' => $host,
]),
'#default_value' => $this->configuration['callback_domain'],
'#required' => FALSE,
];
return $form;
}
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_key_test'] = $values['api_key_test'];
$this->configuration['api_key_live'] = $values['api_key_live'];
$this->configuration['callback_domain'] = $values['callback_domain'];
}
}
public function onNotify(Request $request) {
$mollie_payment_remote_id = $request
->get('id');
if (empty($mollie_payment_remote_id)) {
$data = json_decode($request
->getContent(), TRUE);
$request->request
->replace(is_array($data) ? $data : []);
$mollie_payment_remote_id = $request->request
->get('id');
}
$payment_storage = $this->entityTypeManager
->getStorage('commerce_payment');
$payment = $payment_storage
->loadByRemoteId($mollie_payment_remote_id);
if ($payment === NULL) {
return new JsonResponse();
}
$mollie_payment_remote_object = $this
->getApi()->payments
->get($mollie_payment_remote_id);
switch ($mollie_payment_remote_object->status) {
case MolliePaymentStatus::STATUS_PAID:
$payment_transition = $payment
->getState()
->getWorkflow()
->getTransition('authorize_capture');
$payment
->getState()
->applyTransition($payment_transition);
break;
case MolliePaymentStatus::STATUS_CANCELED:
$payment_transition = $payment
->getState()
->getWorkflow()
->getTransition('void');
$payment
->getState()
->applyTransition($payment_transition);
break;
case MolliePaymentStatus::STATUS_OPEN:
$payment_transition = $payment
->getState()
->getWorkflow()
->getTransition('authorize');
$payment
->getState()
->applyTransition($payment_transition);
break;
case MolliePaymentStatus::STATUS_FAILED:
$payment_transition = $payment
->getState()
->getWorkflow()
->getTransition('void');
$payment
->getState()
->applyTransition($payment_transition);
break;
case MolliePaymentStatus::STATUS_EXPIRED:
$payment_transition = $payment
->getState()
->getWorkflow()
->getTransition('expire');
$payment
->getState()
->applyTransition($payment_transition);
break;
}
$payment
->setRemoteState($mollie_payment_remote_object->status);
$payment
->save();
return new JsonResponse();
}
public function getApi() {
return $this->api;
}
public function createRemotePayment(PaymentInterface $payment, $data) {
$transaction_data = [
'amount' => [
'currency' => $payment
->getAmount()
->getCurrencyCode(),
'value' => number_format($payment
->getAmount()
->getNumber(), 2, '.', ''),
],
'description' => $this
->t('@store order @order_id', [
'@store' => $payment
->getOrder()
->getStore()
->label(),
'@order_id' => $payment
->getOrderId(),
]),
'redirectUrl' => $data['return'],
'webhookUrl' => $this
->getNotifyUrl()
->toString(),
'metadata' => [
'order_id' => $payment
->getOrderId(),
],
];
try {
$mollie_payment = $this
->getApi()->payments
->create($transaction_data);
$payment
->setRemoteId($mollie_payment->id);
$payment
->setRemoteState($mollie_payment->status);
$payment
->save();
ErrorHelper::handleErrors($mollie_payment);
} catch (MollieApiException $e) {
ErrorHelper::handleException($e);
}
return $mollie_payment;
}
public function getNotifyUrl() {
return Url::fromRoute('commerce_payment.notify', [
'commerce_payment_gateway' => $this->entityId,
], [
'absolute' => TRUE,
'base_url' => $this->configuration['callback_domain'],
]);
}
public function buildPaymentInstructions(PaymentInterface $payment = NULL) {
$instructions = [
'#type' => 'processed_text',
'#text' => $this
->t('Thank you for your payment with @gateway. We will inform you when your payment is processed. This is usually done within 24 hours.', [
'@gateway' => $this
->getDisplayLabel(),
], [
'context' => 'Mollie payment instructions',
]),
'#format' => 'plain_text',
];
return $instructions;
}
}