View source
<?php
namespace Drupal\Tests\commerce_recurring\Kernel\Plugin\AdvancedQueue\JobType;
use Drupal\advancedqueue\Job;
use Drupal\commerce_price\Price;
use Drupal\commerce_recurring\Entity\Subscription;
use Drupal\commerce_recurring_test\Entity\ExceptionPaymentMethod;
use Drupal\Tests\commerce_recurring\Kernel\RecurringKernelTestBase;
use Drupal\Core\Test\AssertMailTrait;
use Drupal\Core\Url;
class RetryTest extends RecurringKernelTestBase {
use AssertMailTrait;
public static $modules = [
'commerce_recurring_test',
];
protected $recurringOrderManager;
protected $queue;
protected function setUp() : void {
parent::setUp();
$this->recurringOrderManager = $this->container
->get('commerce_recurring.order_manager');
$queue_storage = $this->container
->get('entity_type.manager')
->getStorage('advancedqueue_queue');
$this->queue = $queue_storage
->load('commerce_recurring');
$this->user
->setEmail($this
->randomMachineName() . '@example.com');
}
public function testRetry() {
$subscription = Subscription::create([
'type' => 'product_variation',
'store_id' => $this->store
->id(),
'billing_schedule' => $this->billingSchedule,
'uid' => $this->user,
'purchased_entity' => $this->variation,
'title' => $this->variation
->getOrderItemTitle(),
'unit_price' => new Price('2', 'USD'),
'state' => 'active',
'starts' => strtotime('2019-02-24 17:00'),
]);
$subscription
->save();
$order = $this->recurringOrderManager
->startRecurring($subscription);
$new_time = strtotime('2019-03-01 00:00');
$this
->rewindTime($new_time);
$job = Job::create('commerce_recurring_order_close', [
'order_id' => $order
->id(),
]);
$this->queue
->enqueueJob($job);
$job = $this->queue
->getBackend()
->claimJob();
$processor = \Drupal::service('advancedqueue.processor');
$result = $processor
->processJob($job, $this->queue);
$order = $this
->reloadEntity($order);
$this
->assertEquals('needs_payment', $order
->getState()
->getId());
$this
->assertEquals(Job::STATE_FAILURE, $result
->getState());
$this
->assertEquals('Payment method not found.', $result
->getMessage());
$this
->assertEquals(3, $result
->getMaxRetries());
$this
->assertEquals(86400, $result
->getRetryDelay());
$this
->assertEquals(1, $job
->getNumRetries());
$this
->assertEquals(Job::STATE_QUEUED, $job
->getState());
$this
->assertEquals(strtotime('2019-03-02 00:00'), $job
->getAvailableTime());
$this
->assertMailString('subject', 'Payment declined - Order #1.', 1);
$this
->assertMailString('body', 'We regret to inform you that the most recent charge attempt on your card failed.', 1);
$this
->assertMailString('body', Url::fromRoute('entity.commerce_payment_method.collection', [
'user' => 1,
], [
'absolute' => TRUE,
])
->toString(), 1);
$next_retry_time = strtotime('+1 day', $new_time);
$this
->assertMailString('body', 'Our next charge attempt will be on: ' . date('F d', $next_retry_time), 1);
$new_time = strtotime('2019-03-02 00:00');
$this
->rewindTime($new_time);
$job = $this->queue
->getBackend()
->claimJob();
$result = $processor
->processJob($job, $this->queue);
$this
->assertEquals(Job::STATE_FAILURE, $result
->getState());
$this
->assertEquals('Payment method not found.', $result
->getMessage());
$this
->assertEquals(3, $result
->getMaxRetries());
$this
->assertEquals(86400 * 3, $result
->getRetryDelay());
$this
->assertEquals(2, $job
->getNumRetries());
$this
->assertEquals(Job::STATE_QUEUED, $job
->getState());
$this
->assertEquals(strtotime('2019-03-05 00:00'), $job
->getAvailableTime());
$next_retry_time = strtotime('+3 days', $new_time);
$this
->assertMailString('body', 'Our next charge attempt will be on: ' . date('F d', $next_retry_time), 1);
$new_time = strtotime('2019-03-05 00:00');
$this
->rewindTime($new_time);
$job = $this->queue
->getBackend()
->claimJob();
$result = $processor
->processJob($job, $this->queue);
$this
->assertEquals(Job::STATE_FAILURE, $result
->getState());
$this
->assertEquals('Payment method not found.', $result
->getMessage());
$this
->assertEquals(3, $result
->getMaxRetries());
$this
->assertEquals(86400 * 5, $result
->getRetryDelay());
$this
->assertEquals(3, $job
->getNumRetries());
$this
->assertEquals(Job::STATE_QUEUED, $job
->getState());
$this
->assertEquals(strtotime('2019-03-10 00:00'), $job
->getAvailableTime());
$next_retry_time = strtotime('+5 days', $new_time);
$this
->assertMailString('body', 'Our final charge attempt will be on: ' . date('F d', $next_retry_time), 1);
$new_time = strtotime('2019-03-10 00:00');
$this
->rewindTime($new_time);
$job = $this->queue
->getBackend()
->claimJob();
$result = $processor
->processJob($job, $this->queue);
$order = $this
->reloadEntity($order);
$this
->assertEquals('failed', $order
->getState()
->getId());
$this
->assertEquals(Job::STATE_SUCCESS, $result
->getState());
$this
->assertEquals('Dunning complete, recurring order not paid.', $result
->getMessage());
$this
->assertEquals(3, $job
->getNumRetries());
$this
->assertEquals(Job::STATE_SUCCESS, $job
->getState());
$subscription = $this
->reloadEntity($subscription);
$this
->assertEquals('canceled', $subscription
->getState()
->getId());
$this
->assertMailString('body', 'This was our final charge attempt.', 1);
}
public function testFailure() {
$payment_method = ExceptionPaymentMethod::create([
'type' => 'credit_card',
'payment_gateway' => 'example',
'card_type' => 'visa',
'card_number' => '1111',
]);
$payment_method
->save();
$subscription = Subscription::create([
'type' => 'product_variation',
'store_id' => $this->store
->id(),
'billing_schedule' => $this->billingSchedule,
'uid' => $this->user,
'purchased_entity' => $this->variation,
'title' => $this->variation
->getOrderItemTitle(),
'unit_price' => new Price('2', 'USD'),
'state' => 'active',
'starts' => strtotime('2019-02-24 17:00'),
'payment_method' => $payment_method,
]);
$subscription
->save();
$order = $this->recurringOrderManager
->startRecurring($subscription);
$this
->rewindTime(strtotime('2019-03-01 00:00'));
$job = Job::create('commerce_recurring_order_close', [
'order_id' => $order
->id(),
]);
$this->queue
->enqueueJob($job);
\Drupal::state()
->set('commerce_recurring_test.payment_method_throw', TRUE);
$job = $this->queue
->getBackend()
->claimJob();
$processor = \Drupal::service('advancedqueue.processor');
$result = $processor
->processJob($job, $this->queue);
$order = $this
->reloadEntity($order);
$this
->assertEquals('failed', $order
->getState()
->getId());
$this
->assertEquals(Job::STATE_FAILURE, $job
->getState());
$this
->assertEquals('This payment is failing dramatically!', $result
->getMessage());
$this
->assertEquals(0, $job
->getNumRetries());
$counts = array_filter($this->queue
->getBackend()
->countJobs());
$this
->assertEquals([
Job::STATE_FAILURE => 1,
], $counts);
$subscription = $this
->reloadEntity($subscription);
$this
->assertEquals('canceled', $subscription
->getState()
->getId());
}
protected function rewindTime($new_time) {
parent::rewindTime($new_time);
$queue_storage = $this->container
->get('entity_type.manager')
->getStorage('advancedqueue_queue');
$queue_storage
->resetCache([
'commerce_recurring',
]);
$this->queue = $queue_storage
->load('commerce_recurring');
$this->container
->set('commerce_recurring.payment_declined_mail', NULL);
$this->container
->set('commerce_recurring.event_subscriber.dunning_subscriber', NULL);
$this->container
->set('event_dispatcher', NULL);
}
}