Exemplo n.º 1
0
            public BillingCharge(Braintree.Transaction transaction)
            {
                Amount         = transaction.Amount.GetValueOrDefault();
                RefundedAmount = 0; // TODO?

                if (transaction.PayPalDetails != null)
                {
                    PaymentSource = new BillingSource(transaction.PayPalDetails);
                }
                else if (transaction.CreditCard != null &&
                         transaction.CreditCard.CardType != Braintree.CreditCardCardType.UNRECOGNIZED)
                {
                    PaymentSource = new BillingSource(transaction.CreditCard);
                }
                else if (transaction.UsBankAccountDetails != null)
                {
                    PaymentSource = new BillingSource(transaction.UsBankAccountDetails);
                }

                CreatedDate    = transaction.CreatedAt.GetValueOrDefault();
                FailureMessage = null;
                Refunded       = transaction.RefundedTransactionId != null;
                Status         = transaction.Status.ToString();
                InvoiceId      = null;
            }
Exemplo n.º 2
0
        public async Task <bool> PreviewUpcomingInvoiceAndPayAsync(ISubscriber subscriber, string planId,
                                                                   List <InvoiceSubscriptionItemOptions> subItemOptions, int prorateThreshold = 500)
        {
            var invoiceService     = new InvoiceService();
            var invoiceItemService = new InvoiceItemService();

            var pendingInvoiceItems = invoiceItemService.ListAutoPaging(new InvoiceItemListOptions
            {
                CustomerId = subscriber.GatewayCustomerId
            }).ToList().Where(i => i.InvoiceId == null);
            var pendingInvoiceItemsDict = pendingInvoiceItems.ToDictionary(pii => pii.Id);

            var upcomingPreview = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions
            {
                CustomerId        = subscriber.GatewayCustomerId,
                SubscriptionId    = subscriber.GatewaySubscriptionId,
                SubscriptionItems = subItemOptions
            });

            var itemsForInvoice = upcomingPreview.Lines?.Data?
                                  .Where(i => pendingInvoiceItemsDict.ContainsKey(i.Id) || (i.Plan.Id == planId && i.Proration));
            var invoiceAmount = itemsForInvoice?.Sum(i => i.Amount) ?? 0;
            var invoiceNow    = invoiceAmount >= prorateThreshold;

            if (invoiceNow)
            {
                // Owes more than prorateThreshold on next invoice.
                // Invoice them and pay now instead of waiting until next billing cycle.

                Invoice invoice             = null;
                var     createdInvoiceItems = new List <InvoiceItem>();
                Braintree.Transaction braintreeTransaction = null;
                try
                {
                    foreach (var ii in itemsForInvoice)
                    {
                        if (pendingInvoiceItemsDict.ContainsKey(ii.Id))
                        {
                            continue;
                        }
                        var invoiceItem = await invoiceItemService.CreateAsync(new InvoiceItemCreateOptions
                        {
                            Currency       = ii.Currency,
                            Description    = ii.Description,
                            CustomerId     = subscriber.GatewayCustomerId,
                            SubscriptionId = ii.SubscriptionId,
                            Discountable   = ii.Discountable,
                            Amount         = ii.Amount
                        });

                        createdInvoiceItems.Add(invoiceItem);
                    }

                    invoice = await invoiceService.CreateAsync(new InvoiceCreateOptions
                    {
                        Billing        = Billing.SendInvoice,
                        DaysUntilDue   = 1,
                        CustomerId     = subscriber.GatewayCustomerId,
                        SubscriptionId = subscriber.GatewaySubscriptionId
                    });

                    var invoicePayOptions = new InvoicePayOptions();
                    var customerService   = new CustomerService();
                    var customer          = await customerService.GetAsync(subscriber.GatewayCustomerId);

                    if (customer != null)
                    {
                        if (customer.Metadata.ContainsKey("btCustomerId"))
                        {
                            invoicePayOptions.PaidOutOfBand = true;
                            var btInvoiceAmount   = (invoiceAmount / 100M);
                            var transactionResult = await _btGateway.Transaction.SaleAsync(
                                new Braintree.TransactionRequest
                            {
                                Amount     = btInvoiceAmount,
                                CustomerId = customer.Metadata["btCustomerId"],
                                Options    = new Braintree.TransactionOptionsRequest
                                {
                                    SubmitForSettlement = true,
                                    PayPal = new Braintree.TransactionOptionsPayPalRequest
                                    {
                                        CustomField = $"{subscriber.BraintreeIdField()}:{subscriber.Id}"
                                    }
                                },
                                CustomFields = new Dictionary <string, string>
                                {
                                    [subscriber.BraintreeIdField()] = subscriber.Id.ToString()
                                }
                            });

                            if (!transactionResult.IsSuccess())
                            {
                                throw new GatewayException("Failed to charge PayPal customer.");
                            }

                            braintreeTransaction = transactionResult.Target;
                            await invoiceService.UpdateAsync(invoice.Id, new InvoiceUpdateOptions
                            {
                                Metadata = new Dictionary <string, string>
                                {
                                    ["btTransactionId"]       = braintreeTransaction.Id,
                                    ["btPayPalTransactionId"] =
                                        braintreeTransaction.PayPalDetails.AuthorizationId
                                }
                            });
                        }
                    }

                    await invoiceService.PayAsync(invoice.Id, invoicePayOptions);
                }
                catch (Exception e)
                {
                    if (braintreeTransaction != null)
                    {
                        await _btGateway.Transaction.RefundAsync(braintreeTransaction.Id);
                    }
                    if (invoice != null)
                    {
                        await invoiceService.DeleteAsync(invoice.Id);

                        // Restore invoice items that were brought in
                        foreach (var item in pendingInvoiceItems)
                        {
                            var i = new InvoiceItemCreateOptions
                            {
                                Currency       = item.Currency,
                                Description    = item.Description,
                                CustomerId     = item.CustomerId,
                                SubscriptionId = item.SubscriptionId,
                                Discountable   = item.Discountable,
                                Metadata       = item.Metadata,
                                Quantity       = item.Quantity,
                                UnitAmount     = item.UnitAmount
                            };
                            await invoiceItemService.CreateAsync(i);
                        }
                    }
                    else
                    {
                        foreach (var ii in createdInvoiceItems)
                        {
                            await invoiceItemService.DeleteAsync(ii.Id);
                        }
                    }
                    throw e;
                }
            }
            return(invoiceNow);
        }
Exemplo n.º 3
0
        public async Task PurchasePremiumAsync(User user, PaymentMethodType paymentMethodType, string paymentToken,
                                               short additionalStorageGb)
        {
            var invoiceService  = new InvoiceService();
            var customerService = new CustomerService();

            var    createdStripeCustomer = false;
            string stripeCustomerId      = null;

            Braintree.Transaction braintreeTransaction = null;
            Braintree.Customer    braintreeCustomer    = null;
            var stripePaymentMethod = paymentMethodType == PaymentMethodType.Card ||
                                      paymentMethodType == PaymentMethodType.BankAccount;

            if (paymentMethodType == PaymentMethodType.BankAccount)
            {
                throw new GatewayException("Bank account payment method is not supported at this time.");
            }

            if (user.Gateway == GatewayType.Stripe && !string.IsNullOrWhiteSpace(user.GatewayCustomerId))
            {
                try
                {
                    await UpdatePaymentMethodAsync(user, paymentMethodType, paymentToken);

                    stripeCustomerId      = user.GatewayCustomerId;
                    createdStripeCustomer = false;
                }
                catch (Exception)
                {
                    stripeCustomerId = null;
                }
            }

            if (string.IsNullOrWhiteSpace(stripeCustomerId))
            {
                string stipeCustomerSourceToken = null;
                var    stripeCustomerMetadata   = new Dictionary <string, string>();

                if (stripePaymentMethod)
                {
                    stipeCustomerSourceToken = paymentToken;
                }
                else if (paymentMethodType == PaymentMethodType.PayPal)
                {
                    var randomSuffix   = Utilities.CoreHelpers.RandomString(3, upper: false, numeric: false);
                    var customerResult = await _btGateway.Customer.CreateAsync(new Braintree.CustomerRequest
                    {
                        PaymentMethodNonce = paymentToken,
                        Email        = user.Email,
                        Id           = user.BraintreeCustomerIdPrefix() + user.Id.ToString("N").ToLower() + randomSuffix,
                        CustomFields = new Dictionary <string, string>
                        {
                            [user.BraintreeIdField()] = user.Id.ToString()
                        }
                    });

                    if (!customerResult.IsSuccess() || customerResult.Target.PaymentMethods.Length == 0)
                    {
                        throw new GatewayException("Failed to create PayPal customer record.");
                    }

                    braintreeCustomer = customerResult.Target;
                    stripeCustomerMetadata.Add("btCustomerId", braintreeCustomer.Id);
                }
                else
                {
                    throw new GatewayException("Payment method is not supported at this time.");
                }

                var customer = await customerService.CreateAsync(new CustomerCreateOptions
                {
                    Description = user.Name,
                    Email       = user.Email,
                    SourceToken = stipeCustomerSourceToken,
                    Metadata    = stripeCustomerMetadata
                });

                stripeCustomerId      = customer.Id;
                createdStripeCustomer = true;
            }

            var subCreateOptions = new SubscriptionCreateOptions
            {
                CustomerId = stripeCustomerId,
                Items      = new List <SubscriptionItemOption>(),
                Metadata   = new Dictionary <string, string>
                {
                    [user.GatewayIdField()] = user.Id.ToString()
                }
            };

            subCreateOptions.Items.Add(new SubscriptionItemOption
            {
                PlanId   = PremiumPlanId,
                Quantity = 1,
            });

            if (additionalStorageGb > 0)
            {
                subCreateOptions.Items.Add(new SubscriptionItemOption
                {
                    PlanId   = StoragePlanId,
                    Quantity = additionalStorageGb
                });
            }

            var          subInvoiceMetadata = new Dictionary <string, string>();
            Subscription subscription       = null;

            try
            {
                if (!stripePaymentMethod)
                {
                    var previewInvoice = await invoiceService.UpcomingAsync(new UpcomingInvoiceOptions
                    {
                        CustomerId        = stripeCustomerId,
                        SubscriptionItems = ToInvoiceSubscriptionItemOptions(subCreateOptions.Items)
                    });

                    await customerService.UpdateAsync(stripeCustomerId, new CustomerUpdateOptions
                    {
                        AccountBalance = -1 * previewInvoice.AmountDue
                    });

                    if (braintreeCustomer != null)
                    {
                        var btInvoiceAmount   = (previewInvoice.AmountDue / 100M);
                        var transactionResult = await _btGateway.Transaction.SaleAsync(
                            new Braintree.TransactionRequest
                        {
                            Amount     = btInvoiceAmount,
                            CustomerId = braintreeCustomer.Id,
                            Options    = new Braintree.TransactionOptionsRequest
                            {
                                SubmitForSettlement = true,
                                PayPal = new Braintree.TransactionOptionsPayPalRequest
                                {
                                    CustomField = $"{user.BraintreeIdField()}:{user.Id}"
                                }
                            },
                            CustomFields = new Dictionary <string, string>
                            {
                                [user.BraintreeIdField()] = user.Id.ToString()
                            }
                        });

                        if (!transactionResult.IsSuccess())
                        {
                            throw new GatewayException("Failed to charge PayPal customer.");
                        }

                        braintreeTransaction = transactionResult.Target;
                        subInvoiceMetadata.Add("btTransactionId", braintreeTransaction.Id);
                        subInvoiceMetadata.Add("btPayPalTransactionId",
                                               braintreeTransaction.PayPalDetails.AuthorizationId);
                    }
                    else
                    {
                        throw new GatewayException("No payment was able to be collected.");
                    }
                }

                var subscriptionService = new SubscriptionService();
                subscription = await subscriptionService.CreateAsync(subCreateOptions);

                if (!stripePaymentMethod && subInvoiceMetadata.Any())
                {
                    var invoices = await invoiceService.ListAsync(new InvoiceListOptions
                    {
                        SubscriptionId = subscription.Id
                    });

                    var invoice = invoices?.FirstOrDefault();
                    if (invoice == null)
                    {
                        throw new GatewayException("Invoice not found.");
                    }

                    await invoiceService.UpdateAsync(invoice.Id, new InvoiceUpdateOptions
                    {
                        Metadata = subInvoiceMetadata
                    });
                }
            }
            catch (Exception e)
            {
                if (createdStripeCustomer && !string.IsNullOrWhiteSpace(stripeCustomerId))
                {
                    await customerService.DeleteAsync(stripeCustomerId);
                }
                if (braintreeTransaction != null)
                {
                    await _btGateway.Transaction.RefundAsync(braintreeTransaction.Id);
                }
                if (braintreeCustomer != null)
                {
                    await _btGateway.Customer.DeleteAsync(braintreeCustomer.Id);
                }
                throw e;
            }

            user.Gateway               = GatewayType.Stripe;
            user.GatewayCustomerId     = stripeCustomerId;
            user.GatewaySubscriptionId = subscription.Id;
            user.Premium               = true;
            user.PremiumExpirationDate = subscription.CurrentPeriodEnd;
        }
Exemplo n.º 4
0
        /// <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);
        }