public virtual bool GetBillingPlanFromCoupon(string couponPassKey, out BillingPlan billingPlan, out Coupon coupon) { Debug.Assert(!string.IsNullOrEmpty(couponPassKey)); using (var ds = DocumentStoreLocator.ResolveOrRoot(CommonConfiguration.CoreDatabaseRoute)) { billingPlan = null; coupon = ds.Load <Coupon>(couponPassKey); } if (null == coupon) { _dblog.InfoFormat("No coupon found for passkey {0}", couponPassKey); return(false); } IUserContext _uc = Catalog.Factory.Resolve <IUserContext>(); var user = _uc.GetCurrentUser(); if (!string.IsNullOrEmpty(coupon.Target)) { if (user.PrincipalId != coupon.Target) { _dblog.InfoFormat("User {0} is not the target of coupon {1}", user.PrincipalId, coupon.PassString); return(false); } } if (coupon.TotalAllowed > 0 && (coupon.CurrentCount >= coupon.TotalAllowed)) { _dblog.InfoFormat("Coupon {0} exceeded allowed counts of {1}", coupon.PassString, coupon.TotalAllowed); return(false); } billingPlan = coupon.BillingPlan; if (null == billingPlan) { var es = string.Format("Coupon does not have a proper billing plan: coupon {0}", coupon.PassString); _log.Error(es); IApplicationAlert on = Catalog.Factory.Resolve <IApplicationAlert>(); on.RaiseAlert(ApplicationAlertKind.System, es); return(false); } _dblog.InfoFormat("Coupon passkey {0} linked to billing plan {1}", couponPassKey, billingPlan.Name); return(true); }
public virtual BillingPlan GetDefaultBillingPlan() { BillingPlan dbp = null; using (var ds = DocumentStoreLocator.ResolveOrRoot(CommonConfiguration.CoreDatabaseRoute)) { dbp = ds.Load <BillingPlan>(DefaultBillingPlanName); } Debug.Assert(null != dbp); if (null == dbp) { var es = "No default billing plan found!"; _log.FatalFormat(es); IApplicationAlert on = Catalog.Factory.Resolve <IApplicationAlert>(); on.RaiseAlert(ApplicationAlertKind.System, es); } return(dbp); }
protected override string BuildPaymentButton(string trxInfo, BillingPlan bp, BrokerTransactionType tt) { Debug.Assert(!string.IsNullOrEmpty(trxInfo)); Debug.Assert(null != bp); _logger.InfoFormat( "Building payment button with transaction info {0}, billing plan {1} and transaction type {2}", trxInfo, bp.Name, tt); PayPalEncryptedButton subscribeButton = new PayPalEncryptedButton(); IConfig config = Catalog.Factory.Resolve <IConfig>(); var businessID = config[PayPalConfiguration.BusinessId]; var cancelReturnUrl = config[PayPalConfiguration.CancelReturnUrl]; var notificationUrl = config[PayPalConfiguration.NotificationUrl]; string itemName, returnUrl, invoice; TemporalId payId = new TemporalId(); if (tt == BrokerTransactionType.Upgrade) { itemName = config[PayPalConfiguration.UpgradeItem]; returnUrl = config[PayPalConfiguration.UpgradeReturnUrl]; invoice = string.Format("{0}:{1}:{2}", UpgradePrefix, bp.Name, payId); } else { itemName = config[PayPalConfiguration.ExpressItem]; returnUrl = config[PayPalConfiguration.ExpressReturnUrl]; invoice = string.Format("{0}:{1}:{2}", ExpressPrefix, bp.Name, payId); } _logger.InfoFormat("invoice: {0}", invoice); const int one = 1; subscribeButton.AddParameter(PayPal.Command, PayPal.ClickSubscription) .AddParameter(PayPal.Business, businessID) .AddParameter(PayPal.SubscribeButtonLanguage, PayPal.USEnglishLanguage) .AddParameter(PayPal.ItemName, itemName) .AddParameter(PayPal.BuyerIncludeNoteWithPayment, PayPal.HideNoteFromUser) .AddParameter(PayPal.ShippingAddressMode, PayPal.ShippingModeHideAddress) .AddParameter(PayPal.ReturnToAppMethod, PayPal.ReturnMethodGetNoVariables) .AddParameter(PayPal.GoToOnPayment, returnUrl) .AddParameter(PayPal.SubscriptionRecurrence, PayPal.SubscriptionRecurs) .AddParameter(PayPal.SubscriptionPrice, string.Format("{0:0.00}", bp.Rate)) .AddParameter(PayPal.SubscriptionDuration, one.ToString()) .AddParameter(PayPal.SubscriptionUnits, PayPal.TimeUnitMonth) .AddParameter(PayPal.CurrencyCode, PayPal.CurrencyUSDollar) .AddParameter(PayPal.TransactionNotificationGatewayURL, notificationUrl) .AddParameter(PayPal.GotoOnCancel, cancelReturnUrl) .AddParameter(PayPal.Custom, trxInfo) .AddParameter(PayPal.InvoiceIdentifier, invoice); if (bp.GracePeriodDays > 0) { subscribeButton.AddParameter(PayPal.TrialPeriodPrice, "0.00") .AddParameter(PayPal.TrialPeriodDuration, bp.GracePeriodDays.ToString()) .AddParameter(PayPal.TrialPeriodUnits, PayPal.TimeUnitDay); } _dblogger.InfoFormat("subscription button: {0}", subscribeButton.Plain); return(subscribeButton.Encrypted); }
protected override void ProcessExpressTrx( string trxInfo, string trxCode, string buyerEmail, string invoice, string unSubRole, string sendAuthCodeTemplate, string subscriptionFailTemplate) { Debug.Assert(!string.IsNullOrEmpty(trxCode)); Debug.Assert(!string.IsNullOrEmpty(trxInfo)); Debug.Assert(!string.IsNullOrEmpty(invoice)); Debug.Assert(!string.IsNullOrEmpty(unSubRole)); Debug.Assert(invoice.Contains(";")); _dblogger.InfoFormat("Processing express transaction: trxInfo {0}, trxCode {1}, invoice {2}", trxInfo, trxCode, invoice); var detail = invoice.Split(';'); BillingPlan bp = null; Debug.Assert(detail.Length == 3); using (var ds = DocumentStoreLocator.ResolveOrRoot(CommonConfiguration.CoreDatabaseRoute)) { try { string billingName = detail[1]; bp = ds.Load <BillingPlan>(billingName); if (null == bp) { var es = string.Format("no billing plan found from invoice {0}", invoice); _logger.Error(es); IApplicationAlert on = Catalog.Factory.Resolve <IApplicationAlert>(); on.RaiseAlert(ApplicationAlertKind.System, es); throw new ApplicationException(); } } catch (Exception ex) { IApplicationAlert on = Catalog.Factory.Resolve <IApplicationAlert>(); on.RaiseAlert(ApplicationAlertKind.System, ex); return; } AuthorizationCode ac = ds.Load <AuthorizationCode>(trxInfo); switch (trxCode) { case PayPal.SubscriptionSignUp: case PayPal.SubscriptionPayment: Debug.Assert(!string.IsNullOrEmpty(buyerEmail)); if (null == ac || ac.Principal == null) { // no user, no auth code. So send the user an authcode to use var newAuthCode = new AuthorizationCode { Code = trxInfo, ExpirationTime = DateTime.UtcNow + TimeSpan.FromDays(90.0), Referent = bp.Name, EmailedTo = buyerEmail }; ds.Store(newAuthCode); ds.SaveChanges(); var email = SendEmail.CreateFromTemplate(_sender, Enumerable.Repeat(buyerEmail, 1).ToArray(), sendAuthCodeTemplate, trxInfo, newAuthCode.Code); email.Send(); _logger.InfoFormat("Sent authcode {0} to user {1}", newAuthCode.Code, buyerEmail); } break; case PayPal.SubscriptionFailed: case PayPal.SubscriptionCancel: case PayPal.SubscriptionEnd: { Debug.Assert(null != ac); var user = ds.Load <ApplicationUser>(ac.Principal); if (null == user) { _logger.ErrorFormat("Payment notification for unknown user {0}", ac.Principal); } else { UnsignUser(user, subscriptionFailTemplate, unSubRole); } } break; } } // doc session }
protected abstract string BuildPaymentButton(string trxInfo, BillingPlan bp, BrokerTransactionType tt);
public virtual string PromoteAccount(string couponPassKey, BrokerTransactionType tt, string newRole, bool resetRole = true) { Debug.Assert(!string.IsNullOrEmpty(couponPassKey)); Debug.Assert(!string.IsNullOrEmpty(newRole)); string retval = null; BillingPlan bp = null; Coupon coupon = null; if (!string.IsNullOrEmpty(couponPassKey)) { if (GetBillingPlanFromCoupon(couponPassKey, out bp, out coupon)) { coupon.CurrentCount++; _dblog.InfoFormat("Coupon {0} now used {1} times of {2}", coupon.PassString, coupon.CurrentCount, coupon.TotalAllowed); } } if (null == bp) { bp = GetDefaultBillingPlan(); if (null == bp) { throw new AccountPromotionException("No default billing plan is available."); } } bool requiresPayment = bp.RecurrenceType > RecurrenceTypes._Paid; IUserContext uc = null; ApplicationUser user = null; if (requiresPayment) { string trxInfo = null; if (tt == BrokerTransactionType.Express) { _authCode = AuthorizationCode.GenerateCode(); trxInfo = AuthCode; _dblog.InfoFormat("Generated authcode {0} for express transaction button", trxInfo); } else if (tt == BrokerTransactionType.Upgrade) { uc = Catalog.Factory.Resolve <IUserContext>(); user = uc.GetCurrentUser(); trxInfo = user.PrincipalId; var subscr = (ApplicationUserSubscription)user.Extensions.GetOrAdd(ApplicationUserSubscription.Extension, _ => new ApplicationUserSubscription()); subscr.BillingPlan = bp; _dblog.InfoFormat("Generating upgrade payment button for user {0} to billing plan {1}", user.PrincipalId, bp.Name); } retval = BuildPaymentButton(trxInfo, bp, tt); } else { retval = null; uc = Catalog.Factory.Resolve <IUserContext>(); user = uc.GetCurrentUser(); var subscr = (ApplicationUserSubscription)user.Extensions.GetOrAdd(ApplicationUserSubscription.Extension, _ => new ApplicationUserSubscription()); Debug.Assert(null != user); if (null == user) { throw new AccountPromotionException("User not signed in."); } subscr.BillingPlan = bp; switch (bp.RecurrenceType) { case RecurrenceTypes.FreeForLife: if (resetRole) { user.AccountRoles.Clear(); } user.AccountRoles.Add(newRole); subscr.BillingPlan = bp; subscr.SubscriptionStart = DateTime.UtcNow; subscr.SubscriptionEnd = DateTime.MaxValue; subscr.BillingStatus = BillingStatus.NeverBilled; _log.InfoFormat("User {0} promoted to free for life", user.PrincipalId); break; case RecurrenceTypes.LimitedTrial: if (subscr.HadTrialAccount == couponPassKey) { _log.WarnFormat("User {0} already used trial account for {1}", user.PrincipalId, couponPassKey); throw new AccountPromotionException("Cannot use a trial account on this user."); } if (resetRole) { user.AccountRoles.Clear(); } user.AccountRoles.Add(newRole); subscr.SubscriptionStart = DateTime.UtcNow; subscr.SubscriptionEnd = DateTime.UtcNow + TimeSpan.FromDays(bp.GracePeriodDays); subscr.HadTrialAccount = couponPassKey; subscr.BillingStatus = BillingStatus.LimitedTrial; _log.InfoFormat("user {0} promoted to limited trial until {1} using coupon {2}", user.PrincipalId, subscr.SubscriptionEnd, couponPassKey); break; case RecurrenceTypes.Owner: user.AccountRoles.Add(newRole); subscr.BillingStatus = BillingStatus.NeverBilled; _log.WarnFormat("user {0} promoted to owner", user.PrincipalId); break; default: var bad = string.Format("Billing plan {0} has invalid recurrence type {1}", bp.Name, bp.RecurrenceType.ToString()); _log.ErrorFormat(bad); throw new AccessViolationException(bad); //break; } } using (var ds = DocumentStoreLocator.ResolveOrRoot(CommonConfiguration.CoreDatabaseRoute)) { // user if (null != user) { ds.Store(user); } // coupon if (null != coupon) { ds.Store(coupon); } ds.SaveChanges(); } return(retval); }