/* Notes: serialized values of SubscriptionStatus * Braintree.SubscriptionStatus.STATUSES.Select(s => s.ToString()); * string "Active" * string "Canceled" * string "Expired" * string "Past Due" * string "Pending" */ /// <summary> /// Run membership requirements checks and returns /// the OwnerStatus that is expected for the user based on that /// (but is not saved and previous status is not checked). /// </summary> /// <param name="userID"></param> /// <returns>Status based on requirements</returns> public static LcEnum.OwnerStatus GetExpectedOwnerStatus(int userID) { // Check all requirements if (UserJobTitle.MeetsOwnershipRequirement(userID) && OwnerAcknowledgment.MeetsOwnsershipRequirement(userID) && UserPaymentPlan.MeetsOwnsershipRequirement(userID)) { // It's OK return(LcEnum.OwnerStatus.active); } else { // It failed var status = UserPaymentPlan.GetLastPaymentPlanStatus(userID); if (status == Braintree.SubscriptionStatus.CANCELED) { return(LcEnum.OwnerStatus.cancelled); } else if (status == Braintree.SubscriptionStatus.EXPIRED) { return(LcEnum.OwnerStatus.suspended); } else { return(LcEnum.OwnerStatus.inactive); } } }
/// <summary> /// Create an instance for a plan subscription and /// a payment transaction. /// If transaction exists on database, it gets the record updating the transaction status. /// </summary> /// <param name="userPlan"></param> /// <param name="transaction"></param> /// <returns></returns> public static UserFeePayment FromSubscriptionTransaction(UserPaymentPlan userPlan, Braintree.Transaction transaction) { var payment = GetBySubscriptionTransaction(userPlan.userID, userPlan.subscriptionID, transaction.Id); if (payment == null) { // New one payment = new UserFeePayment { userID = userPlan.userID, subscriptionID = userPlan.subscriptionID, paymentAmount = transaction.Amount ?? 0, paymentDate = transaction.CreatedAt ?? DateTime.Now, paymentMethod = userPlan.paymentMethod, //paymentMethod = LcPayment.PaymentMethodInfo.Get(transaction.CreditCard.Token).Description, paymentPlan = transaction.PlanId, paymentStatus = transaction.Status.ToString(), paymentTransactionID = transaction.Id }; } else { // Update status payment.paymentStatus = transaction.Status.ToString(); } return(payment); }
public static void Set(UserPaymentPlan data, LcDatabase sharedDb = null) { using (var db = new LcDatabase(sharedDb)) { db.Execute(sqlSet, data.userPaymentPlanID, data.userID, data.subscriptionID, data.paymentPlan.ToString(), data.paymentMethod, data.paymentPlanLastChangedDate, data.nextPaymentDueDate, data.nextPaymentAmount, data.firstBillingDate, data.subscriptionEndDate, data.paymentMethodToken, data.paymentExpiryDate, data.planStatus, data.daysPastDue ); try { // Set OwnerStatus if (IsPartnershipPlan(data.paymentPlan)) { var ow = new Owner(); ow.userID = data.userID; ow.statusID = (int)OwnerStatus.notYetAnOwner; Owner.Set(ow); } else { // Run Membership Checks to enable/disable member (OwnerStatus update) UserProfile.CheckAndSaveOwnerStatus(data.userID); } } catch (Exception ex) { // An error checking status must NOT prevent us from saving/creating // the payment-plan, but we must notify staff so we can take manual action // to fix the error and run the check again for this user try { LcLogger.LogAspnetError(ex); LcMessaging.NotifyError("UserPaymentPlan.Set->UserProfile.CheckAndSaveOwnerStatus::userID=" + data.userID, System.Web.HttpContext.Current.Request.RawUrl, ex.ToString()); } catch { // Prevent cancel paymentplan creation/update because of email or log failing. Really strange // and webhook-scheduleTask for subscriptions would attempt again this. } } } }
public static void Set(UserPaymentPlan data) { using (var db = new LcDatabase()) { db.Execute(sqlSet, data.userID, data.paymentPlan, data.paymentMethod, data.paymentPlanLastChangedDate, data.nextPaymentDueDate, data.nextPaymentAmount, data.lastPaymentDate, data.lastPaymentAmount, data.totalPastDueAmount ); } }
/// <summary> /// Creates a special subscription that has not a payment with the user /// but with a Partner, and as part of it the user (that related with the Partner) /// gets free access for a Loconomics plan. /// </summary> /// <param name="userID"></param> /// <param name="plan"></param> /// <param name="paymentMethod"></param> /// <returns></returns> public static UserPaymentPlan CreatePartnershipSubscription( int userID, SubscriptionPlan plan, LcDatabase db) { // Validate plan if (!IsPartnershipPlan(plan)) { throw new ConstraintException("[[[Invalid subscription plan for a partnership]]]"); } // Setup of the plan var durationDays = 0; switch (plan) { case SubscriptionPlan.CccPlan: durationDays = CccPartnershipSubscriptionDurationDays; break; } // Prepare object var userPlan = new UserPaymentPlan() { userID = userID, paymentPlan = plan, subscriptionEndDate = null, subscriptionID = "", paymentPlanLastChangedDate = DateTimeOffset.Now, nextPaymentDueDate = DateTimeOffset.Now.Add(new TimeSpan(durationDays, 0, 0, 0)), nextPaymentAmount = null, firstBillingDate = DateTimeOffset.Now, planStatus = "ACTIVE", daysPastDue = 0, paymentExpiryDate = null, paymentMethodToken = "", paymentMethod = "", }; // Persist subscription on database Set(userPlan, db); return(userPlan); }
public static void Set(UserPaymentPlan data) { using (var db = new LcDatabase()) { db.Execute(sqlSet, data.userPaymentPlanID, data.userID, data.subscriptionID, data.paymentPlan.ToString(), data.paymentMethod, data.paymentPlanLastChangedDate, data.nextPaymentDueDate, data.nextPaymentAmount, data.firstBillingDate, data.subscriptionEndDate, data.paymentMethodToken, data.paymentExpiryDate, data.planStatus, data.daysPastDue ); } }
public static UserPaymentPlan CreateSubscription( int userID, SubscriptionPlan plan, LcPayment.InputPaymentMethod paymentMethod) { // Prepare payment method (in the remote gateway), get its ID var paymentMethodToken = CollectPaymentMethod(paymentMethod, userID); // Prepare initial object var userPlan = new UserPaymentPlan() { userID = userID, paymentPlan = plan, subscriptionEndDate = null }; // Create subscription at gateway and set details // Wrapped in a try-catch to implement a transaction-like operation: // if something fail after succesfully create the Braintree subscription, like not being // able to save details on database, we need to 'rollback' the subscription, asking for removal // to Braintree string generatedSubscriptionId = null; var paymentPlan = new LcPayment.Membership(); try { if (LcPayment.TESTING_EMULATEBRAINTREE) { userPlan.subscriptionID = LcPayment.CreateFakeSubscriptionId(); userPlan.paymentPlanLastChangedDate = DateTimeOffset.Now; userPlan.nextPaymentDueDate = DateTimeOffset.Now.Add(new TimeSpan(365, 0, 0, 0)); userPlan.nextPaymentAmount = 99; userPlan.firstBillingDate = DateTimeOffset.Now; userPlan.planStatus = "ACTIVE"; userPlan.daysPastDue = 0; } else { // Start creating the subscription at the payment gateway var trialEndDate = GetUserTrialEndDate(userID); // Create the subscription at the payment gateway // It returns the subscription object with a correct ID on success, otherwise an exception is thrown var subscription = paymentPlan.CreateSubscription(plan, paymentMethodToken, trialEndDate); generatedSubscriptionId = subscription.Id; userPlan.subscriptionID = subscription.Id; userPlan.paymentPlanLastChangedDate = subscription.UpdatedAt.Value; userPlan.nextPaymentDueDate = subscription.NextBillingDate; userPlan.nextPaymentAmount = subscription.NextBillAmount; userPlan.firstBillingDate = subscription.FirstBillingDate.Value; userPlan.planStatus = subscription.Status.ToString(); userPlan.daysPastDue = subscription.DaysPastDue ?? 0; } // Fill payment method info var info = LcPayment.PaymentMethodInfo.Get(paymentMethodToken); userPlan.paymentExpiryDate = info.ExpirationDate; userPlan.paymentMethodToken = paymentMethodToken; userPlan.paymentMethod = info.Description; // Persist subscription on database Set(userPlan); } catch (Exception ex) { // Rollback if (generatedSubscriptionId != null) { // Rollback subscription at Payment Gateway paymentPlan.CancelSubscription(generatedSubscriptionId); } // The exception needs to be communicated anyway, so re-throw throw new Exception("[[[Failed subscription]]]", ex); } return(userPlan); }