Esempio n. 1
0
        public InvoiceItemServiceTest(MockHttpClientFixture mockHttpClientFixture)
            : base(mockHttpClientFixture)
        {
            this.service = new InvoiceItemService();

            this.createOptions = new InvoiceItemCreateOptions
            {
                Amount     = 123,
                Currency   = "usd",
                CustomerId = "cus_123",
            };

            this.updateOptions = new InvoiceItemUpdateOptions
            {
                Metadata = new Dictionary <string, string>
                {
                    { "key", "value" },
                },
            };

            this.listOptions = new InvoiceItemListOptions
            {
                Limit = 1,
            };
        }
Esempio n. 2
0
        public virtual async Task <InvoiceLineItem> Create(InvoiceItemCreateOptions options)
        {
            var url = this.ApplyAllParameters(options, Urls.InvoiceItems, false);

            var response = await Requestor.Post(url);

            return(Mapper <InvoiceLineItem> .MapFromJson(response));
        }
        public async Task CreateInvoiceItemAsync(
            string transactionId,
            string description,
            string customer,
            long amount
            )
        {
            var options = new InvoiceItemCreateOptions
            {
                Customer    = customer,
                Currency    = Options.Invoice.Currency,
                Amount      = amount,
                Description = description,
                Metadata    = new Dictionary <string, string>
                {
                    [nameof(transactionId)] = transactionId
                }
            };

            await this.CreateAsync(options);
        }
Esempio n. 4
0
        public InvoiceItemServiceTest()
        {
            this.service = new InvoiceItemService();

            this.createOptions = new InvoiceItemCreateOptions()
            {
                Amount     = 123,
                Currency   = "usd",
                CustomerId = "cus_123",
            };

            this.updateOptions = new InvoiceItemUpdateOptions()
            {
                Metadata = new Dictionary <string, string>()
                {
                    { "key", "value" },
                },
            };

            this.listOptions = new InvoiceItemListOptions()
            {
                Limit = 1,
            };
        }
Esempio n. 5
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);
        }
        private async Task <InvoiceResult> Create(InvoiceInput input, Guid organizationId)
        {
            _logger.LogInformation(GetLogMessage("{organizationId} with options {@input}"), organizationId, input);

            var retVal = new InvoiceResult()
            {
                ProjectId = input.ProjectId
            };

            var project = await _projectService
                          .Repository.Queryable()
                          .Include(x => x.CustomerAccount)
                          .ThenInclude(x => x.PaymentTerm)
                          .Include(x => x.Contracts)
                          .ThenInclude(x => x.InvoiceItems)
                          .Include(x => x.BuyerOrganization)
                          .ThenInclude(x => x.OrganizationBuyerAccount)
                          .Include(x => x.ProviderOrganization)
                          .Include(x => x.Contracts)
                          .ThenInclude(x => x.TimeEntries)
                          .Include(x => x.Contracts)
                          .ThenInclude(x => x.Contractor)
                          .ThenInclude(x => x.Person)
                          .Include(x => x.ProviderOrganization)
                          .ThenInclude(x => x.Organization)
                          .Include(x => x.Contracts)
                          .ThenInclude(x => x.ProviderOrganization)
                          .ThenInclude(x => x.Organization)
                          .Where(x => x.Id == input.ProjectId && x.ProjectManagerOrganizationId == organizationId)
                          .FirstAsync();

            if (project == null)
            {
                throw new ApplicationException("Project Not Found. Id : " + input.ProjectId + " Organization Id : " + organizationId);
            }

            if (project.BuyerOrganization.OrganizationBuyerAccount == null)
            {
                _logger.LogInformation(GetLogMessage("No buyer account found, creating..."));

                var result = await _buyerAccountService.PushCustomer(project.CustomerOrganizationId, project.CustomerId);

                if (result > 0)
                {
                    _logger.LogDebug(GetLogMessage("{0} records updated in database"), result);

                    return(await Create(input, organizationId));
                }

                retVal.ErrorMessage = "Unable to establish buyer account for customer";
                return(retVal);
            }

            List <Contract> contracts;

            // this could be filtered by active, etc

            if (input.IncludeAllContracts)
            {
                contracts = project.Contracts.ToList();
            }
            else
            {
                contracts = project
                            .Contracts
                            .Where(x => input.ContractIds.Contains(x.Id))
                            .ToList();
            }

            _logger.LogDebug(GetLogMessage("Contracts Found: {contracts}"), contracts.Count);
            _logger.LogDebug(GetLogMessage("Buyer Account: {buyerAcct}"), project
                             .BuyerOrganization.OrganizationBuyerAccount.BuyerAccountId);

            var options = new InvoiceCreateOptions()
            {
                Customer         = project.BuyerOrganization.OrganizationBuyerAccount.BuyerAccountId,
                AutoAdvance      = false,
                CollectionMethod = "send_invoice",
                //DaysUntilDue = project.CustomerAccount.PaymentTerm.NetValue > 0 ? project.CustomerAccount.PaymentTerm.NetValue : 1,
                //Footer = project.Proposal.AgreementText,
                DueDate      = DateTime.Today.AddDays(project.CustomerAccount.PaymentTerm.NetValue > 0 ? project.CustomerAccount.PaymentTerm.NetValue : 1),
                CustomFields = new List <InvoiceCustomFieldOptions>()
                {
                    new InvoiceCustomFieldOptions()
                    {
                        Name  = "Project Name",
                        Value = project.Name
                    },
                    new InvoiceCustomFieldOptions()
                    {
                        Name  = "Provider Company",
                        Value = project.ProviderOrganization.Organization.Name
                    }
                },
                Metadata = new Dictionary <string, string>()
                {
                    { "proj_id", project.Id.ToString() }
                }
            };

            var itemsCreated = 0;
            var itemsUpdated = 0;

            foreach (var c in contracts)
            {
                _logger.LogInformation(GetLogMessage("Contract Id: {0}"), c.Id);

                var timeEntries = c.TimeEntries
                                  .Where(x => x.Status == TimeStatus.Approved && x.InvoiceItemId == null)
                                  .ToList();

                _logger.LogDebug(GetLogMessage("{entries} Approved Entries Found"), timeEntries.Count);

                var totalHours = timeEntries.Sum(x => x.TotalHours);
                if (totalHours > 0)
                {
                    var totalCustomerAmount = timeEntries.Sum(x => x.TotalCustomerAmount);
                    var ancientEntry        = c.TimeEntries.Min(x => x.StartDate);
                    var latterDayEntry      = c.TimeEntries.Max(x => x.EndDate);

                    var hours = totalHours.ToString("F");

                    _logger.LogDebug(GetLogMessage("Hours: {0}"), hours);

                    _logger.LogDebug(GetLogMessage("Amount {amount:C}"), totalCustomerAmount);


                    var description =
                        $@"{hours} Hours Worked by {c.Contractor.Person.DisplayName} [{c.ProviderOrganization.Organization.Name}]";

                    var hasInvoiceItems = c.InvoiceItems.Any(x => x.InvoiceId == null);
                    if (hasInvoiceItems)
                    {
                        var invoiceItems = c.InvoiceItems.Where(x => x.InvoiceId == null);
                        _logger.LogDebug(GetLogMessage("Contract has invoice items : {0}"), invoiceItems.Count());
                        foreach (var item in invoiceItems)
                        {
                            _logger.LogDebug(GetLogMessage("Invoice Item Id : {0}"), item.Id);
                            var stripeItem = _invoiceItemService.Update(item.Id, new InvoiceItemUpdateOptions()
                            {
                                Description = description,
                                Amount      = Convert.ToInt64(totalCustomerAmount * 100m)
                            });

                            if (stripeItem != null)
                            {
                                _logger.LogDebug(GetLogMessage("Item Updated in Stripe. Stripe Item Id : {0}"), stripeItem.Id);
                                itemsUpdated++;
                            }
                            else
                            {
                                _logger.LogDebug(GetLogMessage("Item Update Failed in Stripe"));
                            }
                        }
                    }
                    else
                    {
                        _logger.LogDebug(GetLogMessage("Contract doesn't have invoice items. Creating New Invoice Item"));
                        var invoiceItemOptions = new InvoiceItemCreateOptions()
                        {
                            Period = new InvoiceItemPeriodOptions()
                            {
                                Start = ancientEntry.DateTime,
                                End   = latterDayEntry.DateTime
                            },
                            Customer    = project.BuyerOrganization.OrganizationBuyerAccount.BuyerAccountId,
                            Amount      = Convert.ToInt64(totalCustomerAmount * 100),
                            Currency    = "usd",
                            Description = description,
                            Metadata    = new Dictionary <string, string>()
                            {
                                { "contract-id", c.Id.ToString() }
                            }
                        };

                        _logger.LogInformation(GetLogMessage("options: {0}"), invoiceItemOptions);

                        var invoiceItem = _invoiceItemService.Create(invoiceItemOptions);

                        _logger.LogDebug(GetLogMessage("Invoice Item: {0}"), invoiceItem);

                        var invoiceItemResult = await InvoiceItemCreated(invoiceItem);

                        _logger.LogDebug(GetLogMessage("Invoice Item Result: {@result}"), invoiceItemResult);

                        if (invoiceItemResult.Succeeded)
                        {
                            itemsCreated++;
                        }
                    }

                    if (itemsUpdated + itemsCreated > 0)
                    {
                        c.ObjectState = ObjectState.Modified;
                    }
                }
                else
                {
                    _logger.LogDebug(GetLogMessage("no billable time for {contract}"), c.Id);
                }
            }

            var entriesUpdated = _timeEntries.Commit();

            _logger.LogDebug(GetLogMessage("Entries Updated: {entriesUpdated}"), entriesUpdated);
            if (entriesUpdated == 0)
            {
                _logger.LogWarning(GetLogMessage("No Entities were updated"));
            }

            _logger.LogInformation(GetLogMessage("options: {@Options}"), options);

            var invoice = _invoiceService.Create(options);

            if (invoice != null)
            {
                var stripeResult = await InvoiceCreated(invoice, input.RefNo);

                _logger.LogDebug(GetLogMessage("Stripe Result: {@result}"), stripeResult);

                if (stripeResult.Succeeded)
                {
                    retVal.Succeeded = true;
                    retVal.InvoiceId = invoice.Id;
                }
            }
            else
            {
                _logger.LogDebug(GetLogMessage("Unable to create invoice"));
            }


            if (retVal.Succeeded)
            {
                await Task.Run(() => new InvoiceCreatedEvent()
                {
                    InvoiceId = invoice.Id
                });
            }

            return(retVal);
        }
Esempio n. 7
0
        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);
        }
        public string SendInvoice(
            string customerEmail,
            decimal amountToPay,
            string currency,
            string description = "",
            bool sendInvoice   = true)
        {
            try
            {
                CustomerCreateOptions customerInfo = new CustomerCreateOptions
                {
                    Email = customerEmail,
                    //PaymentMethod = "card",
                };
                var customerService = new CustomerService();
                var customer        = customerService.Create(customerInfo);

                var invoiceItemOption = new InvoiceItemCreateOptions
                {
                    Customer = customer.Id,
                    Amount   = Convert.ToInt32(amountToPay * 100),
                    Currency = currency,
                };
                var invoiceItemService = new InvoiceItemService();
                var invoiceItem        = invoiceItemService.Create(invoiceItemOption);

                var invoiceOptions = new InvoiceCreateOptions
                {
                    Customer         = customer.Id,
                    CollectionMethod = "send_invoice",
                    DaysUntilDue     = 30,
                    Description      = description,
                    AutoAdvance      = true
                };

                var service = new InvoiceService();
                var invoice = service.Create(invoiceOptions);
                invoice = service.FinalizeInvoice(invoice.Id);

                try
                {
                    var paymentIntentService = new PaymentIntentService();

                    var paymentIntent = paymentIntentService.Get(invoice.PaymentIntentId);
                    var paymentIntentUpdateOptions = new PaymentIntentUpdateOptions
                    {
                        Description = description
                    };
                    paymentIntentService.Update(paymentIntent.Id, paymentIntentUpdateOptions);
                }
                catch (Exception)
                {
                    //continue
                }

                if (sendInvoice)
                {
                    invoice = service.SendInvoice(invoice.Id);
                }

                return(invoice.Id);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return(null);
            }
        }
        public InvoiceInfo GeneratePayNowLink(
            string customerEmail,
            decimal amountToPay,
            string currency,
            string description = "")
        {
            try
            {
                CustomerCreateOptions customerInfo = new CustomerCreateOptions
                {
                    Email = customerEmail,
                    //PaymentMethod = "card",
                };
                var customerService = new CustomerService();
                var customer        = customerService.Create(customerInfo);

                var invoiceItemOption = new InvoiceItemCreateOptions
                {
                    Customer = customer.Id,
                    Amount   = Convert.ToInt32(amountToPay * 100),
                    Currency = currency,
                };
                var invoiceItemService = new InvoiceItemService();
                var invoiceItem        = invoiceItemService.Create(invoiceItemOption);

                var invoiceOptions = new InvoiceCreateOptions
                {
                    Customer         = customer.Id,
                    CollectionMethod = "send_invoice",
                    DaysUntilDue     = 30,
                    Description      = description
                };

                var service = new InvoiceService();
                var invoice = service.Create(invoiceOptions);

                invoice = service.FinalizeInvoice(invoice.Id);

                try
                {
                    var paymentIntentService = new PaymentIntentService();

                    var paymentIntent = paymentIntentService.Get(invoice.PaymentIntentId);
                    var paymentIntentUpdateOptions = new PaymentIntentUpdateOptions
                    {
                        Description = description
                    };
                    paymentIntentService.Update(paymentIntent.Id, paymentIntentUpdateOptions);
                }
                catch (Exception)
                {
                    //continue
                }

                var result = new InvoiceInfo
                {
                    Url = invoice.HostedInvoiceUrl,
                    Id  = invoice.Id
                };
                return(result);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return(null);
            }
        }