public async Task <IHttpActionResult> BuyFinish(string id, string state) { var hostedPage = (await _chargeBee.HostedPage.Retrieve(id).Request()).HostedPage; if (hostedPage.State != cbm.HostedPage.StateEnum.Succeeded) { // We should only get here if the signup was completed. throw new InvalidOperationException("Asked to complete signup for subscription when checkout did not complete."); } var passThruContent = JsonConvert.DeserializeObject <BuyPassThruContent>(hostedPage.PassThruContent); ChargeBeeUtilities.ParseCustomerId(hostedPage.Content.Subscription.CustomerId, out var accountType, out var accountId); ChangeSummary changes; using (var context = new ShipHubContext()) { changes = await context.BulkUpdateSubscriptions(new[] { new SubscriptionTableType() { AccountId = accountId, State = SubscriptionState.Subscribed.ToString(), TrialEndDate = null, Version = hostedPage.Content.Subscription.ResourceVersion.Value, }, }); } if (!changes.IsEmpty) { await _queueClient.NotifyChanges(changes); } if (passThruContent.AnalyticsId != null) { await _mixpanelClient.TrackAsync( "Purchased", passThruContent.AnalyticsId, new { plan = hostedPage.Content.Subscription.PlanId, customer_id = hostedPage.Content.Subscription.CustomerId, // These refer to the account performing the action, which in the case of // an org subscription, is different than the account being purchased. _github_id = passThruContent.ActorId, _github_login = passThruContent.ActorLogin, }); } var hashParams = new ThankYouPageHashParameters() { Value = hostedPage.Content.Subscription.PlanUnitPrice.Value / 100, PlanId = hostedPage.Content.Subscription.PlanId, }; var hashParamBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes( JsonConvert.SerializeObject(hashParams, GitHubSerialization.JsonSerializerSettings))); return(Redirect($"https://{_configuration.WebsiteHostName}/signup-thankyou.html#{WebUtility.UrlEncode(hashParamBase64)}")); }
public async Task HandleSubscriptionStateChange(ChargeBeeWebhookPayload payload) { var accountId = ChargeBeeUtilities.AccountIdFromCustomerId(payload.Content.Customer.Id); ChangeSummary changes; var tasks = new List <Task>(); using (var context = new ShipHubContext()) { var sub = await context.Subscriptions .AsNoTracking() .SingleOrDefaultAsync(x => x.AccountId == accountId); if (sub == null) { // We only care to update subscriptions we've already sync'ed. This case often happens // in development - e.g., you might be testing subscriptions on your local machine, and // chargebee delivers webhook calls to shiphub-dev about subscriptions it doesn't know // about yet. return; } long incomingVersion; if (payload.EventType == "customer_deleted") { incomingVersion = payload.Content.Customer.ResourceVersion; } else { incomingVersion = payload.Content.Subscription.ResourceVersion; } if (incomingVersion <= sub.Version) { // We're receiving webhook events out-of-order (which can happen due to re-delivery), // so ignore. return; } sub.Version = incomingVersion; var beforeState = sub.State; if (payload.EventType.Equals("subscription_deleted") || payload.EventType.Equals("customer_deleted")) { sub.State = SubscriptionState.NotSubscribed; sub.TrialEndDate = null; } else { switch (payload.Content.Subscription.Status) { case "in_trial": sub.State = SubscriptionState.InTrial; sub.TrialEndDate = DateTimeOffset.FromUnixTimeSeconds((long)payload.Content.Subscription.TrialEnd); break; case "active": case "non_renewing": case "future": sub.State = SubscriptionState.Subscribed; sub.TrialEndDate = null; break; case "cancelled": sub.State = SubscriptionState.NotSubscribed; sub.TrialEndDate = null; break; } } changes = await context.BulkUpdateSubscriptions(new[] { new SubscriptionTableType() { AccountId = sub.AccountId, State = sub.StateName, TrialEndDate = sub.TrialEndDate, Version = sub.Version, } }); } if (!changes.IsEmpty) { await _queueClient.NotifyChanges(changes); } await Task.WhenAll(tasks); }