1
0
mirror of https://git.teknik.io/Teknikode/Teknik.git synced 2023-08-02 14:16:22 +02:00

Added renewals of subscriptions

This commit is contained in:
Uncled1023 2021-11-28 22:26:20 -08:00
parent ef5e5cd82a
commit 98c99b3336
7 changed files with 115 additions and 16 deletions

View File

@ -32,6 +32,7 @@ namespace Teknik.BillingCore
public abstract Subscription GetSubscription(string subscriptionId); public abstract Subscription GetSubscription(string subscriptionId);
public abstract Subscription CreateSubscription(string customerId, string priceId); public abstract Subscription CreateSubscription(string customerId, string priceId);
public abstract Subscription EditSubscriptionPrice(string subscriptionId, string priceId); public abstract Subscription EditSubscriptionPrice(string subscriptionId, string priceId);
public abstract Subscription RenewSubscription(string subscriptionId);
public abstract bool CancelSubscription(string subscriptionId, bool atEndOfPeriod); public abstract bool CancelSubscription(string subscriptionId, bool atEndOfPeriod);
public abstract CheckoutSession CreateCheckoutSession(string customerId, string priceId, string successUrl, string cancelUrl); public abstract CheckoutSession CreateCheckoutSession(string customerId, string priceId, string successUrl, string cancelUrl);

View File

@ -11,6 +11,8 @@ namespace Teknik.BillingCore.Models
public string Id { get; set; } public string Id { get; set; }
public string CustomerId { get; set; } public string CustomerId { get; set; }
public SubscriptionStatus Status { get; set; } public SubscriptionStatus Status { get; set; }
public DateTime BillingPeriodEnd { get; set; }
public bool CancelAtBillingEnd { get; set; }
public List<Price> Prices { get; set; } public List<Price> Prices { get; set; }
public string ClientSecret { get; set; } public string ClientSecret { get; set; }
} }

View File

@ -230,6 +230,27 @@ namespace Teknik.BillingCore
return null; return null;
} }
public override Models.Subscription RenewSubscription(string subscriptionId)
{
if (!string.IsNullOrEmpty(subscriptionId))
{
var subscriptionService = new SubscriptionService();
var subscription = subscriptionService.Get(subscriptionId);
if (subscription != null)
{
var subscriptionOptions = new SubscriptionUpdateOptions()
{
CancelAtPeriodEnd = false
};
subscriptionOptions.AddExpand("latest_invoice.payment_intent");
var result = subscriptionService.Update(subscriptionId, subscriptionOptions);
if (result != null)
return ConvertSubscription(result);
}
}
return null;
}
public override bool CancelSubscription(string subscriptionId, bool atEndOfperiod) public override bool CancelSubscription(string subscriptionId, bool atEndOfperiod)
{ {
if (!string.IsNullOrEmpty(subscriptionId)) if (!string.IsNullOrEmpty(subscriptionId))
@ -454,6 +475,8 @@ namespace Teknik.BillingCore
Id = subscription.Id, Id = subscription.Id,
CustomerId = subscription.CustomerId, CustomerId = subscription.CustomerId,
Status = status, Status = status,
BillingPeriodEnd = subscription.CurrentPeriodEnd,
CancelAtBillingEnd = subscription.CancelAtPeriodEnd,
Prices = prices, Prices = prices,
ClientSecret = subscription.LatestInvoice?.PaymentIntent?.ClientSecret ClientSecret = subscription.LatestInvoice?.PaymentIntent?.ClientSecret
}; };

View File

@ -386,6 +386,8 @@ namespace Teknik.Areas.Users.Controllers
Storage = price.Storage, Storage = price.Storage,
Price = price.Amount, Price = price.Amount,
Interval = price.Interval.ToString(), Interval = price.Interval.ToString(),
BillingPeriodEnd = sub.BillingPeriodEnd,
Canceled = sub.CancelAtBillingEnd
}; };
model.Subscriptions.Add(subView); model.Subscriptions.Add(subView);
} }
@ -1499,7 +1501,7 @@ namespace Teknik.Areas.Users.Controllers
[HttpPost] [HttpPost]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public IActionResult CancelSubscription(string subscriptionId, string productId) public IActionResult CancelSubscription(string subscriptionId)
{ {
// Get Subscription Info // Get Subscription Info
var billingService = BillingFactory.GetBillingService(_config.BillingConfig); var billingService = BillingFactory.GetBillingService(_config.BillingConfig);
@ -1508,13 +1510,6 @@ namespace Teknik.Areas.Users.Controllers
if (subscription == null) if (subscription == null)
return Json(new { error = "Invalid Subscription Id" }); return Json(new { error = "Invalid Subscription Id" });
if (!subscription.Prices.Exists(p => p.ProductId == productId))
return Json(new { error = "Subscription does not relate to product" });
var product = billingService.GetProduct(productId);
if (product == null)
return Json(new { error = "Product does not exist" });
var result = billingService.CancelSubscription(subscriptionId, true); var result = billingService.CancelSubscription(subscriptionId, true);
if (result) if (result)
@ -1522,5 +1517,25 @@ namespace Teknik.Areas.Users.Controllers
return Json(new { error = "Unable to cancel subscription" }); return Json(new { error = "Unable to cancel subscription" });
} }
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult RenewSubscription(string subscriptionId)
{
// Get Subscription Info
var billingService = BillingFactory.GetBillingService(_config.BillingConfig);
var subscription = billingService.GetSubscription(subscriptionId);
if (subscription == null)
return Json(new { error = "Invalid Subscription Id" });
var result = billingService.RenewSubscription(subscriptionId);
if (result != null &&
!result.CancelAtBillingEnd)
return Json(new { result = true });
return Json(new { error = "Unable to cancel subscription" });
}
} }
} }

View File

@ -19,5 +19,9 @@ namespace Teknik.Areas.Users.ViewModels
public string Interval { get; set; } public string Interval { get; set; }
public long Storage { get; set; } public long Storage { get; set; }
public DateTime BillingPeriodEnd { get; set; }
public bool Canceled { get; set; }
} }
} }

View File

@ -7,7 +7,8 @@
} }
<script> <script>
var cancelSubscriptionURL = '@Url.SubRouteUrl("billing", "User.Action", new { action = "CancelSubscription" })'; var cancelSubscriptionURL = '@Url.SubRouteUrl("account", "User.Action", new { action = "CancelSubscription" })';
var renewSubscriptionURL = '@Url.SubRouteUrl("account", "User.Action", new { action = "RenewSubscription" })';
</script> </script>
@if (Config.BillingConfig.Enabled) @if (Config.BillingConfig.Enabled)
@ -28,7 +29,7 @@
} }
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class="col-sm-12">
<h2>Active Subscriptions</h2> <h2>Current Subscriptions</h2>
<hr /> <hr />
</div> </div>
</div> </div>
@ -41,8 +42,24 @@
foreach (var subscription in Model.Subscriptions) foreach (var subscription in Model.Subscriptions)
{ {
<li class="list-group-item" id="@subscription.SubscriptionId"> <li class="list-group-item" id="@subscription.SubscriptionId">
<h4 class="list-group-item-heading pull-left">@subscription.ProductName: <strong>@(StringHelper.GetBytesReadable(subscription.Storage))</strong> for <strong>@($"${subscription.Price:0.00} / {subscription.Interval}")</strong></h4> <div class="pull-left">
<button role="button" class="btn btn-danger cancel-subscription-button pull-right" data-subscription-id="@subscription.SubscriptionId" data-product-id="@subscription.ProductId">Cancel Subscription</button> <h4 class="list-group-item-heading pull-left">@subscription.ProductName: <strong>@(StringHelper.GetBytesReadable(subscription.Storage))</strong> for <strong>@($"${subscription.Price:0.00} / {subscription.Interval}")</strong></h4>
<p>
@if (subscription.Canceled)
{
@:<strong>Canceled</strong> -
}
Billing period ends @(subscription.BillingPeriodEnd.ToShortDateString()).
</p>
</div>
@if (subscription.Canceled)
{
<button role="button" class="btn btn-primary renew-subscription-button pull-right" data-subscription-id="@subscription.SubscriptionId">Renew Subscription</button>
}
else
{
<button role="button" class="btn btn-danger cancel-subscription-button pull-right" data-subscription-id="@subscription.SubscriptionId">Cancel Subscription</button>
}
<div class="clearfix"></div> <div class="clearfix"></div>
</li> </li>
} }

View File

@ -1,17 +1,16 @@
/* globals cancelSubscriptionURL */ /* globals cancelSubscriptionURL, renewSubscriptionURL */
$(document).ready(function () { $(document).ready(function () {
$('.cancel-subscription-button').click(function () { $('.cancel-subscription-button').click(function () {
disableButton('#cancel_subscription', 'Canceling Subscription...'); disableButton('#cancel_subscription', 'Canceling Subscription...');
var subscriptionId = $(this).data('subscription-id'); var subscriptionId = $(this).data('subscription-id');
var productId = $(this).data('product-id');
confirmDialog('Confirm', 'Back', 'Are you sure you want to cancel your subscription? Your plan will be canceled, but is still available until the end of your billing period.', function (result) { confirmDialog('Confirm', 'Back', 'Are you sure you want to cancel your subscription?<br /><br />Your plan will be canceled, but is still available until the end of your billing period.', function (result) {
if (result) { if (result) {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: cancelSubscriptionURL, url: cancelSubscriptionURL,
data: AddAntiForgeryToken({ subscriptionId: subscriptionId, productId: productId }), data: AddAntiForgeryToken({ subscriptionId: subscriptionId }),
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest' 'X-Requested-With': 'XMLHttpRequest'
}, },
@ -38,4 +37,42 @@ $(document).ready(function () {
} }
}); });
}); });
$('.renew-subscription-button').click(function () {
disableButton('#renew_subscription', 'Renewing Subscription...');
var subscriptionId = $(this).data('subscription-id');
confirmDialog('Renew', 'Back', 'Are you sure you want to renew your subscription?', function (result) {
if (result) {
$.ajax({
type: "POST",
url: renewSubscriptionURL,
data: AddAntiForgeryToken({ subscriptionId: subscriptionId }),
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
xhrFields: {
withCredentials: true
},
success: function (response) {
if (response.result) {
$("#top_msg").css('display', 'inline', 'important');
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>Subscription renewed successfully!</div>');
}
else {
$("#top_msg").css('display', 'inline', 'important');
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>' + parseErrorMessage(response) + '</div>');
}
},
error: function (response) {
$("#top_msg").css('display', 'inline', 'important');
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>' + parseErrorMessage(response.responseText) + '</div>');
}
});
} else {
enableButton('#renew_subscription', 'Renew Subscription');
}
});
});
}); });