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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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);
        }