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:
parent
ef5e5cd82a
commit
98c99b3336
@ -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);
|
||||||
|
@ -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; }
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
@ -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" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
}
|
}
|
||||||
|
@ -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">×</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">×</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">×</button>' + parseErrorMessage(response.responseText) + '</div>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
enableButton('#renew_subscription', 'Renew Subscription');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user