public async Task <PaymentGatewayResult <IPaymentInvoice> > CreateInvoiceManualAsync(long amount, string customerId)
        {
            try
            {
                var invoiceItem = await _invoiceItemService.CreateAsync(new InvoiceItemCreateOptions
                {
                    Amount     = amount * 100,
                    Currency   = "usd",
                    CustomerId = customerId,
                });

                var invoiceOptions = new InvoiceCreateOptions
                {
                    CustomerId       = customerId,
                    AutoAdvance      = false, // auto-finalize this draft after ~1 hour
                    CollectionMethod = "send_invoice",
                    DaysUntilDue     = _appSettings.Stripe.InvoiceDueDays,
                    Footer           = $"{Extensions.ApplicationName} Invoices"
                };
                var invoice = await _invoiceService.CreateAsync(invoiceOptions);

                return(PaymentGatewayResult <IPaymentInvoice> .Success(_mapper.Map <IPaymentInvoice>(invoice)));
            }
            catch (StripeException e)
            {
                return(PaymentGatewayResult <IPaymentInvoice> .Failed(e));
            }
        }
Example #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);
        }
        public async Task <Invoice> CreateInvoice(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "invoice/create")]
            CreatePaymentRequest request,
            ILogger log)
        {
            // このサンプルでは input validation をしていません。


            // 既存の Customer に紐づけることもできますが、今回は毎回 Customer を作成します。
            var customerCreateOptions = new CustomerCreateOptions
            {
                Email           = request.Email,
                PaymentMethod   = request.PaymentMethodId,
                InvoiceSettings = new CustomerInvoiceSettingsOptions
                {
                    DefaultPaymentMethod = request.PaymentMethodId
                }
            };

            var customer = await _customerService.CreateAsync(customerCreateOptions);


            // Attach payment method:
            // 新規作成した Customer に PaymentMethod を紐づけます。
            // paymentMethodMethod は既に別の customer に紐づけられている場合エラーになります。
            var options = new PaymentMethodAttachOptions
            {
                Customer = customer.Id
            };

            var paymentMethod = await _paymentMethodService.AttachAsync(request.PaymentMethodId, options);

            // Update customer's default payment method.
            var customerOptions = new CustomerUpdateOptions
            {
                InvoiceSettings = new CustomerInvoiceSettingsOptions
                {
                    DefaultPaymentMethod = paymentMethod.Id,
                }
            };

            await _customerService.UpdateAsync(customer.Id, customerOptions);


            // Create InvoiceItem.
            var createOptions = new InvoiceItemCreateOptions
            {
                Customer = customer.Id,
                Price    = request.PriceId
            };

            await _invoiceItemService.CreateAsync(createOptions);


            // Create Invoice
            var invoiceOptions = new InvoiceCreateOptions
            {
                Customer    = customer.Id,
                AutoAdvance = true,
            };

            var invoiceResult = await _invoiceService.CreateAsync(invoiceOptions);

            //ここで、Stripe の Dashboard > Billing > インボイスにインボイスが追加されます。

            return(invoiceResult);
        }