Skip to content

Commit f720b77

Browse files
committed
Issue #2883597 by bojanz: Reduce payment gateway boilerplate
1 parent a5b023e commit f720b77

File tree

4 files changed

+82
-52
lines changed

4 files changed

+82
-52
lines changed

modules/payment/src/Entity/Payment.php

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,17 @@ public function setCapturedTime($timestamp) {
268268
public function preSave(EntityStorageInterface $storage) {
269269
parent::preSave($storage);
270270

271-
// Initialize the refunded amount.
272-
$refunded_amount = $this->getRefundedAmount();
273-
if (!$refunded_amount) {
274-
$refunded_amount = new Price('0', $this->getAmount()->getCurrencyCode());
275-
$this->setRefundedAmount($refunded_amount);
271+
if ($this->isNew()) {
272+
// Initialize the mode.
273+
$payment_gateway = $this->getPaymentGateway();
274+
$test = $payment_gateway->getPlugin()->getMode() == 'test';
275+
$this->setTest($test);
276+
// Initialize the refunded amount.
277+
$refunded_amount = $this->getRefundedAmount();
278+
if (!$refunded_amount) {
279+
$refunded_amount = new Price('0', $this->getAmount()->getCurrencyCode());
280+
$this->setRefundedAmount($refunded_amount);
281+
}
276282
}
277283
}
278284

modules/payment/src/Plugin/Commerce/PaymentGateway/Manual.php

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,8 @@ public function buildPaymentOperations(PaymentInterface $payment) {
115115
* {@inheritdoc}
116116
*/
117117
public function createPayment(PaymentInterface $payment, $received = FALSE) {
118-
if ($payment->getState()->value != 'new') {
119-
throw new \InvalidArgumentException('The provided payment is in an invalid state.');
120-
}
118+
$this->assertPaymentState($payment, ['new']);
121119

122-
$test = $this->getMode() == 'test';
123-
$payment->setTest($test);
124120
$payment->state = $received ? 'received' : 'pending';
125121
if ($received) {
126122
$payment->setCapturedTime(\Drupal::time()->getRequestTime());
@@ -132,9 +128,7 @@ public function createPayment(PaymentInterface $payment, $received = FALSE) {
132128
* {@inheritdoc}
133129
*/
134130
public function receivePayment(PaymentInterface $payment, Price $amount = NULL) {
135-
if ($payment->getState()->value != 'pending') {
136-
throw new \InvalidArgumentException('Only payments in the "pending" state can be received.');
137-
}
131+
$this->assertPaymentState($payment, ['pending']);
138132

139133
// If not specified, use the entire amount.
140134
$amount = $amount ?: $payment->getAmount();
@@ -148,9 +142,7 @@ public function receivePayment(PaymentInterface $payment, Price $amount = NULL)
148142
* {@inheritdoc}
149143
*/
150144
public function voidPayment(PaymentInterface $payment) {
151-
if ($payment->getState()->value != 'pending') {
152-
throw new \InvalidArgumentException('Only payments in the "pending" state can be canceled.');
153-
}
145+
$this->assertPaymentState($payment, ['pending']);
154146

155147
$payment->state = 'voided';
156148
$payment->save();
@@ -160,17 +152,10 @@ public function voidPayment(PaymentInterface $payment) {
160152
* {@inheritdoc}
161153
*/
162154
public function refundPayment(PaymentInterface $payment, Price $amount = NULL) {
163-
if (!in_array($payment->getState()->value, ['received', 'partially_refunded'])) {
164-
throw new \InvalidArgumentException('Only payments in the "received" and "partially_refunded" states can be refunded.');
165-
}
155+
$this->assertPaymentState($payment, ['received', 'partially_refunded']);
166156
// If not specified, refund the entire amount.
167157
$amount = $amount ?: $payment->getAmount();
168-
169-
// Validate the requested amount.
170-
$balance = $payment->getBalance();
171-
if ($amount->greaterThan($balance)) {
172-
throw new InvalidRequestException(sprintf("Can't refund more than %s.", $balance->__toString()));
173-
}
158+
$this->assertRefundAmount($payment, $amount);
174159

175160
$old_refunded_amount = $payment->getRefundedAmount();
176161
$new_refunded_amount = $old_refunded_amount->add($amount);

modules/payment/src/Plugin/Commerce/PaymentGateway/PaymentGatewayBase.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44

55
use Drupal\commerce_payment\CreditCard;
66
use Drupal\commerce_payment\Entity\PaymentInterface;
7+
use Drupal\commerce_payment\Entity\PaymentMethodInterface;
8+
use Drupal\commerce_payment\Exception\HardDeclineException;
9+
use Drupal\commerce_payment\Exception\InvalidRequestException;
710
use Drupal\commerce_payment\PaymentMethodTypeManager;
811
use Drupal\commerce_payment\PaymentTypeManager;
12+
use Drupal\commerce_price\Price;
913
use Drupal\Component\Utility\NestedArray;
1014
use Drupal\Core\Entity\EntityTypeManagerInterface;
1115
use Drupal\Core\Form\FormStateInterface;
@@ -339,4 +343,60 @@ public function buildPaymentOperations(PaymentInterface $payment) {
339343
return $operations;
340344
}
341345

346+
/**
347+
* Asserts that the payment state matches one of the allowed states.
348+
*
349+
* @param \Drupal\commerce_payment\Entity\PaymentInterface $payment
350+
* The payment.
351+
* @param string[] $states
352+
* The allowed states.
353+
*
354+
* @throws \InvalidArgumentException
355+
* Thrown if the payment state does not match the allowed states.
356+
*/
357+
protected function assertPaymentState(PaymentInterface $payment, array $states) {
358+
$state = $payment->getState()->value;
359+
if (!in_array($state, $states)) {
360+
throw new \InvalidArgumentException(sprintf('The provided payment is in an invalid state ("%s").', $state));
361+
}
362+
}
363+
364+
/**
365+
* Asserts that the payment method is neither empty nor expired.
366+
*
367+
* @param \Drupal\commerce_payment\Entity\PaymentMethodInterface $payment_method
368+
* The payment method.
369+
*
370+
* @throws \InvalidArgumentException
371+
* Thrown when the payment method is empty.
372+
* @throws \Drupal\commerce_payment\Exception\HardDeclineException
373+
* Thrown when the payment method has expired.
374+
*/
375+
protected function assertPaymentMethod(PaymentMethodInterface $payment_method = NULL) {
376+
if (empty($payment_method)) {
377+
throw new \InvalidArgumentException('The provided payment has no payment method referenced.');
378+
}
379+
if ($payment_method->isExpired()) {
380+
throw new HardDeclineException('The provided payment method has expired');
381+
}
382+
}
383+
384+
/**
385+
* Asserts that the refund amount is valid.
386+
*
387+
* @param \Drupal\commerce_payment\Entity\PaymentInterface $payment
388+
* The payment.
389+
* @param \Drupal\commerce_price\Price $refund_amount
390+
* The allowed states.
391+
*
392+
* @throws \Drupal\commerce_payment\Exception\InvalidRequestException
393+
* Thrown when the refund amount is larger than the payment balance.
394+
*/
395+
protected function assertRefundAmount(PaymentInterface $payment, Price $refund_amount) {
396+
$balance = $payment->getBalance();
397+
if ($refund_amount->greaterThan($balance)) {
398+
throw new InvalidRequestException(sprintf("Can't refund more than %s.", $balance->__toString()));
399+
}
400+
}
401+
342402
}

modules/payment_example/src/Plugin/Commerce/PaymentGateway/Onsite.php

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use Drupal\commerce_payment\Entity\PaymentInterface;
77
use Drupal\commerce_payment\Entity\PaymentMethodInterface;
88
use Drupal\commerce_payment\Exception\HardDeclineException;
9-
use Drupal\commerce_payment\Exception\InvalidRequestException;
109
use Drupal\commerce_payment\PaymentMethodTypeManager;
1110
use Drupal\commerce_payment\PaymentTypeManager;
1211
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OnsitePaymentGatewayBase;
@@ -85,16 +84,9 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s
8584
* {@inheritdoc}
8685
*/
8786
public function createPayment(PaymentInterface $payment, $capture = TRUE) {
88-
if ($payment->getState()->value != 'new') {
89-
throw new \InvalidArgumentException('The provided payment is in an invalid state.');
90-
}
87+
$this->assertPaymentState($payment, ['new']);
9188
$payment_method = $payment->getPaymentMethod();
92-
if (empty($payment_method)) {
93-
throw new \InvalidArgumentException('The provided payment has no payment method referenced.');
94-
}
95-
if (\Drupal::time()->getRequestTime() >= $payment_method->getExpiresTime()) {
96-
throw new HardDeclineException('The provided payment method has expired');
97-
}
89+
$this->assertPaymentMethod($payment_method);
9890

9991
// Add a built in test for testing decline exceptions.
10092
/** @var \Drupal\address\Plugin\Field\FieldType\AddressItem $billing_address */
@@ -114,8 +106,6 @@ public function createPayment(PaymentInterface $payment, $capture = TRUE) {
114106
$remote_id = '123456';
115107

116108
$payment->state = $capture ? 'capture_completed' : 'authorization';
117-
$test = $this->getMode() == 'test';
118-
$payment->setTest($test);
119109
$payment->setRemoteId($remote_id);
120110
$payment->setAuthorizedTime(\Drupal::time()->getRequestTime());
121111
if ($capture) {
@@ -128,9 +118,7 @@ public function createPayment(PaymentInterface $payment, $capture = TRUE) {
128118
* {@inheritdoc}
129119
*/
130120
public function capturePayment(PaymentInterface $payment, Price $amount = NULL) {
131-
if ($payment->getState()->value != 'authorization') {
132-
throw new \InvalidArgumentException('Only payments in the "authorization" state can be captured.');
133-
}
121+
$this->assertPaymentState($payment, ['authorization']);
134122
// If not specified, capture the entire amount.
135123
$amount = $amount ?: $payment->getAmount();
136124

@@ -149,10 +137,7 @@ public function capturePayment(PaymentInterface $payment, Price $amount = NULL)
149137
* {@inheritdoc}
150138
*/
151139
public function voidPayment(PaymentInterface $payment) {
152-
if ($payment->getState()->value != 'authorization') {
153-
throw new \InvalidArgumentException('Only payments in the "authorization" state can be voided.');
154-
}
155-
140+
$this->assertPaymentState($payment, ['authorization']);
156141
// Perform the void request here, throw an exception if it fails.
157142
// See \Drupal\commerce_payment\Exception for the available exceptions.
158143
$remote_id = $payment->getRemoteId();
@@ -165,16 +150,10 @@ public function voidPayment(PaymentInterface $payment) {
165150
* {@inheritdoc}
166151
*/
167152
public function refundPayment(PaymentInterface $payment, Price $amount = NULL) {
168-
if (!in_array($payment->getState()->value, ['capture_completed', 'capture_partially_refunded'])) {
169-
throw new \InvalidArgumentException('Only payments in the "capture_completed" and "capture_partially_refunded" states can be refunded.');
170-
}
153+
$this->assertPaymentState($payment, ['capture_completed', 'capture_partially_refunded']);
171154
// If not specified, refund the entire amount.
172155
$amount = $amount ?: $payment->getAmount();
173-
// Validate the requested amount.
174-
$balance = $payment->getBalance();
175-
if ($amount->greaterThan($balance)) {
176-
throw new InvalidRequestException(sprintf("Can't refund more than %s.", $balance->__toString()));
177-
}
156+
$this->assertRefundAmount($payment, $amount);
178157

179158
// Perform the refund request here, throw an exception if it fails.
180159
// See \Drupal\commerce_payment\Exception for the available exceptions.

0 commit comments

Comments
 (0)