public function RetryTest::testRetry in Commerce Recurring Framework 8
@covers ::process @covers ::handleDecline @covers ::updateSubscriptions
File
- tests/
src/ Kernel/ Plugin/ AdvancedQueue/ JobType/ RetryTest.php, line 62
Class
- RetryTest
- @coversDefaultClass \Drupal\commerce_recurring\Plugin\AdvancedQueue\JobType\RecurringJobTypeBase @group commerce_recurring
Namespace
Drupal\Tests\commerce_recurring\Kernel\Plugin\AdvancedQueue\JobTypeCode
public function testRetry() {
// A subscription without a payment method, to ensure a decline.
/** @var \Drupal\commerce_recurring\Entity\SubscriptionInterface $subscription */
$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);
// Rewind time to the end of the first 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();
/** @var \Drupal\advancedqueue\ProcessorInterface $processor */
$processor = \Drupal::service('advancedqueue.processor');
$result = $processor
->processJob($job, $this->queue);
// Confirm that the order was placed.
$order = $this
->reloadEntity($order);
$this
->assertEquals('needs_payment', $order
->getState()
->getId());
// Confirm that the job result is correct.
$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());
// Confirm that the job was re-queued.
$this
->assertEquals(1, $job
->getNumRetries());
$this
->assertEquals(Job::STATE_QUEUED, $job
->getState());
$this
->assertEquals(strtotime('2019-03-02 00:00'), $job
->getAvailableTime());
// Confirm dunning email.
$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);
// Run the first retry.
$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());
// Confirm that the job was re-queued.
$this
->assertEquals(2, $job
->getNumRetries());
$this
->assertEquals(Job::STATE_QUEUED, $job
->getState());
$this
->assertEquals(strtotime('2019-03-05 00:00'), $job
->getAvailableTime());
// Confirm dunning email.
$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);
// Run the second retry.
$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());
// Confirm that the job was re-queued.
$this
->assertEquals(3, $job
->getNumRetries());
$this
->assertEquals(Job::STATE_QUEUED, $job
->getState());
$this
->assertEquals(strtotime('2019-03-10 00:00'), $job
->getAvailableTime());
// Confirm dunning email.
$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);
// Run the last retry.
$new_time = strtotime('2019-03-10 00:00');
$this
->rewindTime($new_time);
$job = $this->queue
->getBackend()
->claimJob();
$result = $processor
->processJob($job, $this->queue);
// Confirm that the order was marked as failed.
$order = $this
->reloadEntity($order);
$this
->assertEquals('failed', $order
->getState()
->getId());
// Confirm that the job result is correct.
$this
->assertEquals(Job::STATE_SUCCESS, $result
->getState());
$this
->assertEquals('Dunning complete, recurring order not paid.', $result
->getMessage());
// Confirm that the job was not requeued.
$this
->assertEquals(3, $job
->getNumRetries());
$this
->assertEquals(Job::STATE_SUCCESS, $job
->getState());
// Confirm that the subscription was canceled.
$subscription = $this
->reloadEntity($subscription);
$this
->assertEquals('canceled', $subscription
->getState()
->getId());
// Confirm dunning email.
$this
->assertMailString('body', 'This was our final charge attempt.', 1);
}