Buy

Back on the account page, our customers would love us if we would show them when they will be billed next. In other words: when will my subscription renew?

Open the Subscription class - aka the subscription table. I've already added a billingPeriodEndsAt column:

102 lines src/AppBundle/Entity/Subscription.php
... lines 1 - 10
class Subscription
{
... lines 13 - 40
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $billingPeriodEndsAt;
... lines 45 - 86
/**
* @return \DateTime
*/
public function getBillingPeriodEndsAt()
{
return $this->billingPeriodEndsAt;
}
... lines 94 - 100
}

All we need to do is set this when the subscription is first created. Ok, we also need to update it each month when the subscription is renewed - but we'll talk about that later with webhooks.

The Subscription is created - or retrieved - right here in SubscriptionHelper. This is the spot to set that date.

And hey! This method is passed a \Stripe\Subscription object:

72 lines src/AppBundle/Subscription/SubscriptionHelper.php
... lines 1 - 8
class SubscriptionHelper
{
... lines 11 - 45
public function addSubscriptionToUser(\Stripe\Subscription $stripeSubscription, User $user)
{
... lines 48 - 60
}
... lines 62 - 70
}

Let's check out the API docs to see what that gives us. Oh yes, it has a current_period_end property, which is a UNIX timestamp. Bingo!

Setting the billingPeriodEndsAt

In SubscriptionHelper, before we activate the subscription, add a new $periodEnd variable. To convert the timestamp to a \DateTime object, say $periodEnd = \DateTime::createFromFormat('U') - for UNIX timestamp - $stripeSubscription->current_period_end:

74 lines src/AppBundle/Subscription/SubscriptionHelper.php
... lines 1 - 8
class SubscriptionHelper
{
... lines 11 - 45
public function addSubscriptionToUser(\Stripe\Subscription $stripeSubscription, User $user)
{
$subscription = $user->getSubscription();
if (!$subscription) {
$subscription = new Subscription();
$subscription->setUser($user);
}
$periodEnd = \DateTime::createFromFormat('U', $stripeSubscription->current_period_end);
... lines 55 - 62
}
... lines 64 - 72
}

Now, pass that into the activateSubscription() method as a new argument:

74 lines src/AppBundle/Subscription/SubscriptionHelper.php
... lines 1 - 53
$periodEnd = \DateTime::createFromFormat('U', $stripeSubscription->current_period_end);
$subscription->activateSubscription(
$stripeSubscription->plan->id,
$stripeSubscription->id,
$periodEnd
);
... lines 60 - 74

Open that function in Subscription and add a new \DateTime argument called $periodEnd. Set the property with $this->billingPeriodEndsAt = $periodEnd:

103 lines src/AppBundle/Entity/Subscription.php
... lines 1 - 10
class Subscription
{
... lines 13 - 94
public function activateSubscription($stripePlanId, $stripeSubscriptionId, \DateTime $periodEnd)
{
... lines 97 - 98
$this->billingPeriodEndsAt = $periodEnd;
... line 100
}
}

Done!

Rendering the Next Billing Date

To celebrate, open the account.html.twig template. For "Next Billing At", add if app.user.subscription - so if they have a subscription - then print app.user.subscription.billingPeriodEndsAt|date('F jS') to format the date nicely:

57 lines app/Resources/views/profile/account.html.twig
... lines 1 - 2
{% block body %}
<div class="nav-space">
<div class="container">
... lines 6 - 11
<div class="row">
<div class="col-xs-6">
<table class="table">
<tbody>
... lines 16 - 25
<tr>
<th>Next Billing at:</th>
<td>
{% if app.user.subscription %}
{{ app.user.subscription.billingPeriodEndsAt|date('F jS') }}
{% else %}
n/a
{% endif %}
</td>
</tr>
... lines 36 - 45
</tbody>
</table>
</div>
... lines 49 - 51
</div>
</div>
</div>
{% endblock %}
... lines 56 - 57

OK team! Refresh that page! The "Next Billing At" is... wrong! August 9th! That's today! But no worries, that's just because the field is blank in the database, so it's using today. To really test if this is working, we need to checkout with a new subscription.

Now, in real life, you probably won't allow your users to buy multiple subscriptions. Afterall, we're only storing info in the database about one Subscription, per user. But, for testing, it's really handy to be able to checkout over and over again.

The checkout worked! Click "Account". Yes! There is the correct date: September 9th, one month from today. And the VISA card ends in 4242.

Alright: the informational part of the account page is done. But, the user still needs to be able to do some pretty important stuff, like cancelling their subscription - yes, this does happen, it's nothing personal - and updating their credit card. Let's get to it.

Leave a comment!