예제 #1
0
        public void TestInvoicePaymentSucceeded()
        {
            var invoice = new StripeInvoice
            {
                Subscription = "sub_123",
                Amount       = 123,
                Charge       = "ch_123",
            };

            _donationService.Setup(mocked => mocked.CreateDonationForInvoice(invoice)).Returns(987);

            _fixture.InvoicePaymentSucceeded(DateTime.Now, invoice);
            _paymentProcessorService.VerifyAll();
            _donationService.VerifyAll();
        }
예제 #2
0
        public static async Task <string> RequiredInvoice(string subscriptionId)
        {
            StripeConfiguration.SetApiKey("sk_test_5nCTR2UZmnOPWgZASvirbYDy");

            StripeInvoiceService       invoiceService = new StripeInvoiceService();
            StripeList <StripeInvoice> invoiceItems   = await invoiceService.ListAsync(
                new StripeInvoiceListOptions()
            {
                SubscriptionId = subscriptionId
            }
                );

            StripeInvoice value = invoiceItems.First <StripeInvoice>();

            return(value.Id);
        }
예제 #3
0
        public static async Task <string> UpdateInvoice(string invoiceId)
        {
            StripeConfiguration.SetApiKey("sk_test_5nCTR2UZmnOPWgZASvirbYDy");

            StripeInvoiceUpdateOptions invoiceOptions = new StripeInvoiceUpdateOptions()
            {
                Closed = false
            };

            StripeInvoiceService invoiceService = new StripeInvoiceService();
            //"in_1D18zxHWpLOEdy24Tgw0TzEq"
            //             |
            //             V
            StripeInvoice invoice = await invoiceService.UpdateAsync(invoiceId, invoiceOptions);

            return("OK");
        }
예제 #4
0
        public void SendSubscriptionPaymentReceiptEmail(StripeInvoice invoice, StripeCustomer customer)
        {
            var message = new MailMessage()
            {
                IsBodyHtml = true
            };

            message.To.Add(new MailAddress(customer.Email));
            message.Subject = string.Format("Software Payment Receipt");
            message.Body    = string.Format("<p>{0}</p>",
                                            string.Format("Thank you for using our software.  Your credit card has been charged ${0}",
                                                          Math.Ceiling((decimal)invoice.AmountDue / 100)));

            using (var smtp = new SmtpClient())
            {
                smtp.Send(message);
            }
        }
예제 #5
0
        private void InvoicePaymentFailed(DateTime?created, StripeInvoice invoice)
        {
            var charge = _paymentProcessorService.GetCharge(invoice.Charge);
            var notes  = "No Stripe Failure Code";

            if (charge != null)
            {
                notes = $"{charge.FailureCode ?? "No Stripe Failure Code"}: {charge.FailureMessage ?? "No Stripe Failure Message"}";
            }
            _mpDonorRepository.ProcessRecurringGiftDecline(invoice.Subscription, notes);
            var gift = _mpDonorRepository.GetRecurringGiftForSubscription(invoice.Subscription);

            if (gift.ConsecutiveFailureCount > 2)
            {
                var subscription = _paymentProcessorService.CancelSubscription(gift.StripeCustomerId, gift.SubscriptionId);
                _paymentProcessorService.CancelPlan(subscription.Plan.Id);
                _mpDonorRepository.CancelRecurringGift(gift.RecurringGiftId.Value);
            }
        }
        private async Task InvoicePaymentSucceededAsync(StripeInvoice inv)
        {
            var org = await _organizationRepository.GetByStripeCustomerIdAsync(inv.CustomerId).AnyContext();

            if (org == null)
            {
                _logger.Error("Unknown customer id in payment succeeded notification: {0}", inv.CustomerId);
                return;
            }

            var user = await _userRepository.GetByIdAsync(org.BillingChangedByUserId).AnyContext();

            if (user == null)
            {
                _logger.Error("Unable to find billing user: {0}", org.BillingChangedByUserId);
                return;
            }

            _logger.Info("Stripe payment succeeded. Customer: {0} Org: {1} Org Name: {2}", inv.CustomerId, org.Id, org.Name);
        }
예제 #7
0
        private void InvoicePaymentSucceeded(StripeInvoice inv)
        {
            var org = _organizationRepository.GetByStripeCustomerId(inv.CustomerId);

            if (org == null)
            {
                Log.Error().Message("Unknown customer id in payment failed notification: {0}", inv.CustomerId).Write();
                return;
            }

            var user = _userRepository.GetById(org.BillingChangedByUserId);

            if (user == null)
            {
                Log.Error().Message("Unable to find billing user: {0}", org.BillingChangedByUserId).Write();
                return;
            }

            Log.Info().Message("Stripe payment succeeded. Customer: {0} Org: {1} Org Name: {2}", inv.CustomerId, org.Id, org.Name).Write();
        }
        public static PaymentInvoice ToPaymentInvoice(this StripeInvoice stripeInvoice)
        {
            var invoice = new PaymentInvoice
            {
                Id              = stripeInvoice.Id,
                InvoiceNumber   = stripeInvoice.Number,
                ReceiptNumber   = stripeInvoice.ReceiptNumber,
                AmountDue       = stripeInvoice.AmountDue.ToDecimalAmount(),
                AmountPaid      = stripeInvoice.AmountPaid.ToDecimalAmount(),
                AmountRemaining = stripeInvoice.AmountRemaining.ToDecimalAmount(),
                AttemptCount    = stripeInvoice.AttemptCount,
                Attempted       = stripeInvoice.Attempted,
                CustomerId      = stripeInvoice.CustomerId,
                ChargeId        = stripeInvoice.ChargeId,
                Description     = stripeInvoice.Description,
                //Todo: Discount
                DueDate          = stripeInvoice.DueDate,
                HostedInvoiceUrl = stripeInvoice.HostedInvoiceUrl,
                HostedPdf        = stripeInvoice.InvoicePdf,
                Subtotal         = stripeInvoice.Subtotal.ToDecimalAmount(),
                Total            = stripeInvoice.Total.ToDecimalAmount(),
                periodStartDate  = stripeInvoice.PeriodStart,
                periodEndDate    = stripeInvoice.PeriodEnd,
                Tax        = stripeInvoice.Tax == null ? null : (decimal?)((int)stripeInvoice.Tax).ToDecimalAmount(),
                TaxPercent = stripeInvoice.TaxPercent
            };

            //Items
            if (stripeInvoice.StripeInvoiceLineItems != null && stripeInvoice.StripeInvoiceLineItems.TotalCount > 0)
            {
                invoice.Items = new List <InvoiceItem>();
                foreach (var lineItem in stripeInvoice.StripeInvoiceLineItems)
                {
                    if (lineItem != null)
                    {
                        invoice.Items.Add(lineItem.ToInvoiceItem());
                    }
                }
            }
            return(invoice);
        }
        private async Task InvoicePaymentFailedAsync(StripeInvoice inv)
        {
            var org = await _organizationRepository.GetByStripeCustomerIdAsync(inv.CustomerId).AnyContext();

            if (org == null)
            {
                _logger.Error().Message("Unknown customer id in payment failed notification: {0}", inv.CustomerId).Write();
                return;
            }

            var user = await _userRepository.GetByIdAsync(org.BillingChangedByUserId).AnyContext();

            if (user == null)
            {
                _logger.Error().Message("Unable to find billing user: {0}", org.BillingChangedByUserId).Write();
                return;
            }

            _logger.Info().Message("Stripe payment failed. Customer: {0} Org: {1} Org Name: {2} Email: {3}", inv.CustomerId, org.Id, org.Name, user.EmailAddress).Write();
            await _mailer.SendPaymentFailedAsync(user, org).AnyContext();
        }
예제 #10
0
        public void HandleEvent(StripeEvent stripeEvent)
        {
            switch (stripeEvent.Type)
            {
            case "customer.subscription.updated": {
                StripeSubscription stripeSubscription = Mapper <StripeSubscription> .MapFromJson(stripeEvent.Data.Object.ToString());

                SubscriptionUpdated(stripeSubscription);
                break;
            }

            case "customer.subscription.deleted": {
                StripeSubscription stripeSubscription = Mapper <StripeSubscription> .MapFromJson(stripeEvent.Data.Object.ToString());

                SubscriptionDeleted(stripeSubscription);
                break;
            }

            case "invoice.payment_succeeded": {
                StripeInvoice stripeInvoice = Mapper <StripeInvoice> .MapFromJson(stripeEvent.Data.Object.ToString());

                InvoicePaymentSucceeded(stripeInvoice);
                break;
            }

            case "invoice.payment_failed": {
                StripeInvoice stripeInvoice = Mapper <StripeInvoice> .MapFromJson(stripeEvent.Data.Object.ToString());

                InvoicePaymentFailed(stripeInvoice);
                break;
            }

            default: {
                Log.Trace().Message("Unhandled stripe webhook called. Type: {0} Id: {1} UserId: {2}", stripeEvent.Type, stripeEvent.Id, stripeEvent.UserId).Write();
                break;
            }
            }
        }
        public async Task HandleEventAsync(StripeEvent stripeEvent)
        {
            switch (stripeEvent.Type)
            {
            case "customer.subscription.updated": {
                StripeSubscription stripeSubscription = Mapper <StripeSubscription> .MapFromJson(stripeEvent.Data.Object.ToString());
                await SubscriptionUpdatedAsync(stripeSubscription).AnyContext();

                break;
            }

            case "customer.subscription.deleted": {
                StripeSubscription stripeSubscription = Mapper <StripeSubscription> .MapFromJson(stripeEvent.Data.Object.ToString());
                await SubscriptionDeletedAsync(stripeSubscription).AnyContext();

                break;
            }

            case "invoice.payment_succeeded": {
                StripeInvoice stripeInvoice = Mapper <StripeInvoice> .MapFromJson(stripeEvent.Data.Object.ToString());
                await InvoicePaymentSucceededAsync(stripeInvoice).AnyContext();

                break;
            }

            case "invoice.payment_failed": {
                StripeInvoice stripeInvoice = Mapper <StripeInvoice> .MapFromJson(stripeEvent.Data.Object.ToString());
                await InvoicePaymentFailedAsync(stripeInvoice).AnyContext();

                break;
            }

            default: {
                _logger.Trace("Unhandled stripe webhook called. Type: {0} Id: {1} Account: {2}", stripeEvent.Type, stripeEvent.Id, stripeEvent.Account);
                break;
            }
            }
        }
예제 #12
0
        public InvoiceModel(Organization organization, StripeInvoice invoice, ApiSettings apiSettings)
        {
            OurAddress1 = apiSettings.OurAddress1;
            OurAddress2 = apiSettings.OurAddress2;
            OurAddress3 = apiSettings.OurAddress3;

            CustomerName      = organization.BusinessName ?? "--";
            CustomerAddress1  = organization.BusinessAddress1;
            CustomerAddress2  = organization.BusinessAddress2;
            CustomerAddress3  = organization.BusinessAddress3;
            CustomerCountry   = organization.BusinessCountry;
            CustomerVatNumber = organization.BusinessTaxNumber;

            InvoiceDate    = invoice.Date?.ToLongDateString();
            InvoiceDueDate = invoice.DueDate?.ToLongDateString();
            InvoiceNumber  = invoice.Id;
            Items          = invoice.StripeInvoiceLineItems.Select(i => new Item(i));

            SubtotalAmount = (invoice.Total / 100).ToString("C");
            VatTotalAmount = 0.ToString("C");
            TotalAmount    = SubtotalAmount;
            Paid           = invoice.Paid;
        }
예제 #13
0
        public ActionResult Payment(string id)
        {
            if (String.IsNullOrEmpty(id))
            {
                return(HttpNotFound());
            }

            if (!id.StartsWith("in_"))
            {
                id = "in_" + id;
            }

            var           invoiceService = new StripeInvoiceService();
            StripeInvoice invoice        = invoiceService.Get(id);

            if (invoice == null)
            {
                return(HttpNotFound());
            }

            Organization org = _repository.GetByStripeCustomerId(invoice.CustomerId);

            if (org == null)
            {
                return(HttpNotFound());
            }

            if (!CanAccessOrganization(org.Id))
            {
                return(HttpNotFound());
            }

            return(View(new InvoiceModel {
                Invoice = invoice, Organization = org
            }));
        }
예제 #14
0
        static void TestInvoices2(StripePayment payment)
        {
            StripeCustomer cust     = payment.GetCustomer("cus_ulcOcy5Seu2dpq");
            StripePlanInfo planInfo = new StripePlanInfo {
                Amount   = 1999,
                ID       = "testplan",
                Interval = StripePlanInterval.Month,
                Name     = "The Test Plan",
                //TrialPeriod = 7
            };
            //payment.DeletePlan (planInfo.ID);
            StripePlan             plan    = payment.CreatePlan(planInfo);
            StripeSubscriptionInfo subInfo = new StripeSubscriptionInfo {
                Card    = GetCC(),
                Plan    = planInfo.ID,
                Prorate = true
            };
            StripeSubscription sub = payment.Subscribe(cust.ID, subInfo);

            payment.CreateInvoiceItem(new StripeInvoiceItemInfo {
                CustomerID  = cust.ID,
                Amount      = 1337,
                Description = "Test single charge"
            });

            int total;
            List <StripeInvoice> invoices = payment.GetInvoices(0, 10, cust.ID, out total);
            StripeInvoice        upcoming = payment.GetUpcomingInvoice(cust.ID);

            payment.Unsubscribe(cust.ID, true);
            payment.DeletePlan(planInfo.ID);
            foreach (StripeInvoiceLineItem line in upcoming)
            {
                Console.WriteLine("{0} for type {1}", line.Amount, line.GetType());
            }
        }
예제 #15
0
        // GET: /StripeWebhooks/
        public async Task <HttpStatusCodeResult> Index()
        {
            var json        = new StreamReader(Request.InputStream).ReadToEnd();
            var stripeEvent = StripeEventUtility.ParseEvent(json);

            #region All Event types
            // All the event types explained here: https://stripe.com/docs/api#event_types
            switch (stripeEvent.Type)
            {
            case "account.updated":     //Occurs whenever an account status or property has changed.
                break;

            case "account.application.deauthorized":     // Occurs whenever a user deauthorizes an application. Sent to the related application only.
                break;

            case "application_fee.created":     // Occurs whenever an application fee is created on a charge.
                break;

            case "application_fee.refunded":     // Occurs whenever an application fee is refunded, whether from refunding a charge or from refunding the application fee directly, including partial refunds.
                break;

            case "balance.available":     // Occurs whenever your Stripe balance has been updated (e.g. when a charge collected is available to be paid out). By default, Stripe will automatically transfer any funds in your balance to your bank account on a daily basis.
                break;

            case "charge.succeeded":     // Occurs whenever a new charge is created and is successful.
                break;

            case "charge.failed":     // Occurs whenever a failed charge attempt occurs.
                break;

            case "charge.refunded":     // Occurs whenever a charge is refunded, including partial refunds.
                break;

            case "charge.captured":     // Occurs whenever a previously uncaptured charge is captured.
                break;

            case "charge.updated":     // Occurs whenever a charge description or metadata is updated.
                break;

            case "charge.dispute.created":     // Occurs whenever a customer disputes a charge with their bank (chargeback).
                break;

            case "charge.dispute.updated":     // Occurs when the dispute is updated (usually with evidence).
                break;

            case "charge.dispute.closed":     // Occurs when the dispute is resolved and the dispute status changes to won or lost.
                break;

            case "customer.created":     // Occurs whenever a new customer is created.
                break;

            case "customer.updated":     // Occurs whenever any property of a customer changes.
                break;

            case "customer.deleted":     // Occurs whenever a customer is deleted.
                break;

            case "customer.card.created":     // Occurs whenever a new card is created for the customer.
                break;

            case "customer.card.updated":     // Occurs whenever a card's details are changed.
                // TODO: Save card updated, might happen when the card is close to expire
                break;

            case "customer.card.deleted":     // Occurs whenever a card is removed from a customer.
                break;

            case "customer.subscription.created":     // Occurs whenever a customer with no subscription is signed up for a plan.
                break;

            case "customer.subscription.updated":     // Occurs whenever a subscription changes. Examples would include switching from one plan to another, or switching status from trial to active.
                break;

            case "customer.subscription.deleted":     // Occurs whenever a customer ends their subscription.
                break;

            case "customer.subscription.trial_will_end":     // Occurs three days before the trial period of a subscription is scheduled to end.
                // TODO: If the user hasn't added credit card details -> Send email reminder.
                break;

            case "customer.discount.created":     // Occurs whenever a coupon is attached to a customer.
                break;

            case "customer.discount.updated":     // Occurs whenever a customer is switched from one coupon to another.
                break;

            case "customer.discount.deleted":
                break;

            case "invoice.created":     // Occurs whenever a new invoice is created. If you are using webhooks, Stripe will wait one hour after they have all succeeded to attempt to pay the invoice; the only exception here is on the first invoice, which gets created and paid immediately when you subscribe a customer to a plan. If your webhooks do not all respond successfully, Stripe will continue retrying the webhooks every hour and will not attempt to pay the invoice. After 3 days, Stripe will attempt to pay the invoice regardless of whether or not your webhooks have succeeded. See how to respond to a webhook.
                break;

            case "invoice.payment_failed":     // Occurs whenever an invoice attempts to be paid, and the payment fails. This can occur either due to a declined payment, or because the customer has no active card. A particular case of note is that if a customer with no active card reaches the end of its free trial, an invoice.payment_failed notification will occur.
                // TODO: Notify customer
                break;

            case "invoice.payment_succeeded":     // Occurs whenever an invoice attempts to be paid, and the payment succeeds.
                StripeInvoice stripeInvoice = Stripe.Mapper <StripeInvoice> .MapFromJson(stripeEvent.Data.Object.ToString());

                Invoice invoice = SaasEcom.Core.Infrastructure.Mappers.Map(stripeInvoice);
                if (invoice != null && invoice.Total > 0)
                {
                    // TODO get the customer billing address, we still have to instantiate the address on the invoice
                    invoice.BillingAddress = new BillingAddress();

                    await InvoiceDataService.CreateOrUpdateAsync(invoice);

                    // TODO: Send invoice by email
                }
                break;

            case "invoice.updated":     // Occurs whenever an invoice changes (for example, the amount could change).
                break;

            case "invoiceitem.created":     // Occurs whenever an invoice item is created.
                break;

            case "invoiceitem.updated":     // Occurs whenever an invoice item is updated.
                break;

            case "invoiceitem.deleted":     // Occurs whenever an invoice item is deleted.
                break;

            case "plan.created":     // Occurs whenever a plan is created.
                break;

            case "plan.updated":     // Occurs whenever a plan is updated.
                break;

            case "plan.deleted":     // Occurs whenever a plan is deleted.
                break;

            case "coupon.created":     // Occurs whenever a coupon is created.
                break;

            case "coupon.deleted":     // Occurs whenever a coupon is deleted.
                break;

            case "transfer.created":     // Occurs whenever a new transfer is created.
                break;

            case "transfer.updated":     // Occurs whenever the description or metadata of a transfer is updated.
                break;

            case "transfer.paid":     // Occurs whenever a sent transfer is expected to be available in the destination bank account. If the transfer failed, a transfer.failed webhook will additionally be sent at a later time.
                break;

            case "transfer.failed":     // Occurs whenever Stripe attempts to send a transfer and that transfer fails.
                break;
            }
            #endregion

            return(new HttpStatusCodeResult(HttpStatusCode.Accepted));
        }
예제 #16
0
        public async Task <IActionResult> PostWebhook([FromQuery] string key)
        {
            if (key != _billingSettings.StripeWebhookKey)
            {
                return(new BadRequestResult());
            }

            StripeEvent parsedEvent;

            using (var sr = new StreamReader(HttpContext.Request.Body))
            {
                var json = await sr.ReadToEndAsync();

                parsedEvent = StripeEventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"],
                                                                _billingSettings.StripeWebhookSecret);
            }

            if (string.IsNullOrWhiteSpace(parsedEvent?.Id))
            {
                return(new BadRequestResult());
            }

            if (_hostingEnvironment.IsProduction() && !parsedEvent.LiveMode)
            {
                return(new BadRequestResult());
            }

            var invUpcoming = parsedEvent.Type.Equals("invoice.upcoming");
            var subDeleted  = parsedEvent.Type.Equals("customer.subscription.deleted");
            var subUpdated  = parsedEvent.Type.Equals("customer.subscription.updated");

            if (subDeleted || subUpdated)
            {
                StripeSubscription subscription = Mapper <StripeSubscription> .MapFromJson(
                    parsedEvent.Data.Object.ToString());

                if (subscription == null)
                {
                    throw new Exception("Subscription is null.");
                }

                var ids = GetIdsFromMetaData(subscription.Metadata);

                var subCanceled = subDeleted && subscription.Status == "canceled";
                var subUnpaid   = subUpdated && subscription.Status == "unpaid";

                if (subCanceled || subUnpaid)
                {
                    // org
                    if (ids.Item1.HasValue)
                    {
                        await _organizationService.DisableAsync(ids.Item1.Value, subscription.CurrentPeriodEnd);
                    }
                    // user
                    else if (ids.Item2.HasValue)
                    {
                        await _userService.DisablePremiumAsync(ids.Item2.Value, subscription.CurrentPeriodEnd);
                    }
                }

                if (subUpdated)
                {
                    // org
                    if (ids.Item1.HasValue)
                    {
                        await _organizationService.UpdateExpirationDateAsync(ids.Item1.Value,
                                                                             subscription.CurrentPeriodEnd);
                    }
                    // user
                    else if (ids.Item2.HasValue)
                    {
                        await _userService.UpdatePremiumExpirationAsync(ids.Item2.Value,
                                                                        subscription.CurrentPeriodEnd);
                    }
                }
            }
            else if (false /* Disabled for now */ && invUpcoming)
            {
                StripeInvoice invoice = Mapper <StripeInvoice> .MapFromJson(
                    parsedEvent.Data.Object.ToString());

                if (invoice == null)
                {
                    throw new Exception("Invoice is null.");
                }

                // TODO: maybe invoice subscription expandable is already here any we don't need to call API?
                var subscriptionService = new StripeSubscriptionService();
                var subscription        = await subscriptionService.GetAsync(invoice.SubscriptionId);

                if (subscription == null)
                {
                    throw new Exception("Invoice subscription is null.");
                }

                var ids = GetIdsFromMetaData(subscription.Metadata);

                // To include in email:
                // invoice.AmountDue;
                // invoice.DueDate;

                // org
                if (ids.Item1.HasValue)
                {
                    // TODO: email billing contact
                }
                // user
                else if (ids.Item2.HasValue)
                {
                    // TODO: email user
                }
            }

            return(new OkResult());
        }
예제 #17
0
        public async Task <InvoiceResult> InvoiceCreated(Invoice invoice, string refNo)
        {
            _logger.LogInformation(GetLogMessage("Invoice: {invoice}"), invoice.Id);

            var retVal = new InvoiceResult
            {
                InvoiceId = invoice.Id
            };

            var entity = new StripeInvoice
            {
                Id               = invoice.Id,
                ObjectState      = ObjectState.Added,
                Updated          = DateTimeOffset.UtcNow,
                AmountDue        = Convert.ToDecimal(invoice.AmountDue / 100m),
                AmountRemaining  = Convert.ToDecimal(invoice.AmountRemaining / 100m),
                Attempted        = invoice.Attempted,
                CustomerId       = invoice.CustomerId,
                InvoicePdf       = invoice.InvoicePdf,
                Status           = invoice.Status,
                SubscriptionId   = invoice.SubscriptionId,
                AmountPaid       = Convert.ToDecimal(invoice.AmountPaid / 100m),
                Total            = Convert.ToDecimal(invoice.Total / 100m),
                Subtotal         = Convert.ToDecimal(invoice.Subtotal / 100m),
                HostedInvoiceUrl = invoice.HostedInvoiceUrl,
                BillingReason    = invoice.BillingReason,
                AttemptCount     = invoice.AttemptCount,
                Number           = invoice.Number,
                DueDate          = invoice.DueDate
            };


            if (invoice.Metadata.ContainsKey("proj_id"))
            {
                Guid projectId = Guid.Parse(invoice.Metadata["proj_id"]);
                _logger.LogInformation(GetLogMessage("Project Id : {0}"), projectId.ToString());

                var project = await _projectService.Repository.Queryable()
                              .Where(x => x.Id == projectId).FirstAsync();

                retVal.ProjectId = projectId;

                entity.ProjectInvoice = new ProjectInvoice()
                {
                    AccountManagerId       = project.AccountManagerId,
                    ProviderOrganizationId = project.ProjectManagerOrganizationId,
                    CustomerId             = project.CustomerId,
                    BuyerOrganizationId    = project.CustomerOrganizationId,
                    ProjectManagerId       = project.ProjectManagerId,
                    ProjectId   = projectId,
                    RefNo       = refNo,
                    ObjectState = ObjectState.Added
                };
            }
            else
            {
                _logger.LogDebug(GetLogMessage("Not a project invoice"));
            }

            var records = _invoices.InsertOrUpdateGraph(entity, true);

            _logger.LogDebug(GetLogMessage("{0} records updated"), records);

            if (records > 0)
            {
                UpdateInvoiceItems(invoice, true);
                retVal.Succeeded = true;
            }

            return(await Task.FromResult(retVal));
        }
예제 #18
0
        public ActionResult Index()
        {
            Stream request = Request.InputStream;

            request.Seek(0, SeekOrigin.Begin);
            string      json        = new StreamReader(request).ReadToEnd();
            StripeEvent stripeEvent = null;

            try
            {
                stripeEvent = StripeEventUtility.ParseEvent(json);
                stripeEvent = VerifyEventSentFromStripe(stripeEvent);
                if (HasEventBeenProcessedPreviously(stripeEvent))
                {
                    return(new HttpStatusCodeResult(HttpStatusCode.OK));
                }
                ;
            }
            catch (Exception ex)
            {
                return(new HttpStatusCodeResult(HttpStatusCode.BadRequest, string.Format("Unable to parse incoming event.  The following error occurred: {0}", ex.Message)));
            }

            if (stripeEvent == null)
            {
                return(new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Incoming event empty"));
            }

            var emailService = new StripeFundamentals.Web.Services.EmailService();

            switch (stripeEvent.Type)
            {
            case StripeEvents.ChargeRefunded:
                var charge = Mapper <StripeCharge> .MapFromJson(stripeEvent.Data.Object.ToString());

                emailService.SendRefundEmail(charge);
                break;

            case StripeEvents.CustomerSubscriptionTrialWillEnd:
                var subscription = Mapper <StripeSubscription> .MapFromJson(stripeEvent.Data.Object.ToString());

                emailService.SendTrialEndEmail(subscription);
                break;

            case StripeEvents.InvoicePaymentSucceeded:
                StripeInvoice invoice = Mapper <StripeInvoice> .MapFromJson(stripeEvent.Data.Object.ToString());

                var customer = StripeCustomerService.Get(invoice.CustomerId);
                var user     = UserManager.FindByEmail(customer.Email);

                user.ActiveUntil = user.ActiveUntil.AddMonths(1);
                UserManager.Update(user);

                emailService.SendSubscriptionPaymentReceiptEmail(invoice, customer);
                break;

            case StripeEvents.InvoicePaymentFailed:
                var failedInvoice = Mapper <StripeInvoice> .MapFromJson(stripeEvent.Data.Object.ToString());

                //TODO: implement sending email to customer and customer service
                break;

            default:
                break;
            }

            //TODO: log Stripe eventid to StripeEvent table in application database
            return(new HttpStatusCodeResult(HttpStatusCode.OK));
        }
예제 #19
0
        public async Task <IActionResult> PostWebhook([FromQuery] string key)
        {
            if (key != _billingSettings.StripeWebhookKey)
            {
                return(new BadRequestResult());
            }

            StripeEvent parsedEvent;

            using (var sr = new StreamReader(HttpContext.Request.Body))
            {
                var json = await sr.ReadToEndAsync();

                parsedEvent = StripeEventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"],
                                                                _billingSettings.StripeWebhookSecret);
            }

            if (string.IsNullOrWhiteSpace(parsedEvent?.Id))
            {
                return(new BadRequestResult());
            }

            if (_hostingEnvironment.IsProduction() && !parsedEvent.LiveMode)
            {
                return(new BadRequestResult());
            }

            var invUpcoming = parsedEvent.Type.Equals("invoice.upcoming");
            var subDeleted  = parsedEvent.Type.Equals("customer.subscription.deleted");
            var subUpdated  = parsedEvent.Type.Equals("customer.subscription.updated");

            if (subDeleted || subUpdated)
            {
                StripeSubscription subscription = Mapper <StripeSubscription> .MapFromJson(
                    parsedEvent.Data.Object.ToString());

                if (subscription == null)
                {
                    throw new Exception("Subscription is null.");
                }

                var ids = GetIdsFromMetaData(subscription.Metadata);

                var subCanceled = subDeleted && subscription.Status == "canceled";
                var subUnpaid   = subUpdated && subscription.Status == "unpaid";

                if (subCanceled || subUnpaid)
                {
                    // org
                    if (ids.Item1.HasValue)
                    {
                        await _organizationService.DisableAsync(ids.Item1.Value, subscription.CurrentPeriodEnd);
                    }
                    // user
                    else if (ids.Item2.HasValue)
                    {
                        await _userService.DisablePremiumAsync(ids.Item2.Value, subscription.CurrentPeriodEnd);
                    }
                }

                if (subUpdated)
                {
                    // org
                    if (ids.Item1.HasValue)
                    {
                        await _organizationService.UpdateExpirationDateAsync(ids.Item1.Value,
                                                                             subscription.CurrentPeriodEnd);
                    }
                    // user
                    else if (ids.Item2.HasValue)
                    {
                        await _userService.UpdatePremiumExpirationAsync(ids.Item2.Value,
                                                                        subscription.CurrentPeriodEnd);
                    }
                }
            }
            else if (invUpcoming)
            {
                StripeInvoice invoice = Mapper <StripeInvoice> .MapFromJson(
                    parsedEvent.Data.Object.ToString());

                if (invoice == null)
                {
                    throw new Exception("Invoice is null.");
                }

                var subscriptionService = new StripeSubscriptionService();
                var subscription        = await subscriptionService.GetAsync(invoice.SubscriptionId);

                if (subscription == null)
                {
                    throw new Exception("Invoice subscription is null.");
                }

                string email = null;
                var    ids   = GetIdsFromMetaData(subscription.Metadata);
                // org
                if (ids.Item1.HasValue)
                {
                    var org = await _organizationRepository.GetByIdAsync(ids.Item1.Value);

                    if (org != null && OrgPlanForInvoiceNotifications(org))
                    {
                        email = org.BillingEmail;
                    }
                }
                // user
                else if (ids.Item2.HasValue)
                {
                    var user = await _userService.GetUserByIdAsync(ids.Item2.Value);

                    if (user.Premium)
                    {
                        email = user.Email;
                    }
                }

                if (!string.IsNullOrWhiteSpace(email) && invoice.NextPaymentAttempt.HasValue)
                {
                    var items = invoice.StripeInvoiceLineItems.Select(i => i.Description).ToList();
                    await _mailService.SendInvoiceUpcomingAsync(email, invoice.AmountDue / 100M,
                                                                invoice.NextPaymentAttempt.Value, items, ids.Item1.HasValue);
                }
            }

            return(new OkResult());
        }
예제 #20
0
 public BillingInvoice(StripeInvoice inv)
 {
     Amount = inv.AmountDue / 100M;
     Date   = inv.Date.Value;
 }
        /// <summary>
        /// Create order in fortnox
        /// </summary>
        /// <param name="stripeEvent"></param>
        /// <returns></returns>
        public async Task <HttpResponseMessage> HandleInvoiceCreatedAsync(StripeInvoice invoice)
        {
            _log.LogInformation($"Invoice created with ID {invoice.Id}, type: {invoice.Billing}");

            if (await OrderExists(invoice.Id))
            {
                _log.LogInformation($"Duplicate request for invoice id {invoice.Id}");
                return(new HttpResponseMessage(HttpStatusCode.OK)
                {
                    Content = new StringContent("Duplicate request ignored")
                });
            }

            var customerId = await GetFortnoxCustomerId(invoice.CustomerId);

            var order = new
            {
                CustomerNumber            = customerId,
                Language                  = "EN",
                ExternalInvoiceReference1 = invoice.Id,
                Remarks          = invoice.Billing == StripeBilling.ChargeAutomatically ? "Don't pay this invoice!\n\nYou have prepaid by credit/debit card." : "",
                CopyRemarks      = true,
                Currency         = invoice.Currency.ToUpperInvariant(),
                EmailInformation = new
                {
                    EmailAddressFrom = "*****@*****.**",
                    EmailAddressBCC  = "*****@*****.**",
                    EmailSubject     = "Flexinets Invoice/Order Receipt {no}",
                    EmailBody        = invoice.Billing == StripeBilling.ChargeAutomatically
                        ? "Dear Flexinets user,<br />This email contains the credit card receipt for your prepaid subscription. No action required.<br /><br />Best regards<br />Flexinets<br />www.flexinets.eu"
                        : "hitta på text för fakturan"
                },
                OrderRows = invoice.StripeInvoiceLineItems.Data.Select(line => new
                {
                    Description       = line.Description.Replace("×", "x"), // thats not an x, this is an x
                    AccountNumber     = "",
                    ArticleNumber     = ArticleNumber,
                    Price             = line.Amount / 100m,
                    OrderedQuantity   = line.Quantity.GetValueOrDefault(0),
                    DeliveredQuantity = line.Quantity.GetValueOrDefault(0),
                    VAT          = invoice.TaxPercent.HasValue ? Convert.ToInt32(invoice.TaxPercent.Value) : 0,
                    Discount     = invoice.StripeDiscount?.StripeCoupon?.PercentOff != null ? invoice.StripeDiscount.StripeCoupon.PercentOff.Value : 0,
                    DiscountType = "PERCENT"
                }).ToList()
            };

            if (invoice.StripeDiscount?.StripeCoupon?.PercentOff != null)
            {
                order.OrderRows.Add(new
                {
                    Description       = $"Promo code {invoice.StripeDiscount.StripeCoupon.Id} applied: {invoice.StripeDiscount.StripeCoupon.Name}",
                    AccountNumber     = "0",
                    ArticleNumber     = "",
                    Price             = 0m,
                    OrderedQuantity   = 0,
                    DeliveredQuantity = 0,
                    VAT          = 0,
                    Discount     = 0m,
                    DiscountType = ""
                });
            }

            order.OrderRows.Add(new
            {
                Description       = $"Order date {invoice.Date.Value.ToUniversalTime():yyyy-MM-dd HH:mm:ss} UTC",
                AccountNumber     = "0",
                ArticleNumber     = "",
                Price             = 0m,
                OrderedQuantity   = 0,
                DeliveredQuantity = 0,
                VAT          = 0,
                Discount     = 0m,
                DiscountType = ""
            });
예제 #22
0
        public static string GenerateStripeHTMLInvoice(StripeInvoice stripeInvoice)
        {
            var invoiceHtml = new StringBuilder();

            #region Build out Invoice HTML

            //Generate dollar amounts
            var invoiceSubtotal  = Sahara.Core.Common.Methods.Billing.ConvertStripeAmountToDollars(stripeInvoice.Subtotal.ToString());
            var invoiceTotal     = Sahara.Core.Common.Methods.Billing.ConvertStripeAmountToDollars(stripeInvoice.Total.ToString());
            var invoiceAmountDue = Sahara.Core.Common.Methods.Billing.ConvertStripeAmountToDollars(stripeInvoice.AmountDue.ToString());


            invoiceHtml.Append("<table style='width:90%; border-spacing:0px; font-size:13px;'>");

            invoiceHtml.Append("<tr>");

            invoiceHtml.Append("<td style='padding:2px; width:80%; border-bottom: solid 2px black; border-top: solid 3px black;'>");
            invoiceHtml.Append("<strong>Description</strong>");
            invoiceHtml.Append("</td>");

            ///invoiceHtml.Append("<td style='border-bottom: solid 1px black; border-top: solid 3px black;'>");
            ///invoiceHtml.Append("Quantity");
            //invoiceHtml.Append("</td>");

            invoiceHtml.Append("<td style='padding:2px; width:20%; border-bottom: solid 2px black; border-top: solid 3px black; text-align:center'>");
            invoiceHtml.Append("<strong>Price</strong>");
            invoiceHtml.Append("</td>");

            invoiceHtml.Append("</tr>");



            var last = stripeInvoice.StripeInvoiceLineItems.Data.Last();
            foreach (var lineItem in stripeInvoice.StripeInvoiceLineItems.Data)
            {
                //Generate dollar amount
                var lineItemAmount = Sahara.Core.Common.Methods.Billing.ConvertStripeAmountToDollars(lineItem.Amount.ToString());

                //Generate description
                string descriptionCopy = lineItem.Description;

                if (String.IsNullOrEmpty(descriptionCopy))
                {
                    if (lineItem.Plan != null)
                    {
                        descriptionCopy = lineItem.Plan.Name + " Plan";
                    }
                    else
                    {
                        descriptionCopy = "No description available";
                    }
                }

                invoiceHtml.Append("<tr>");

                if (!lineItem.Equals(last))
                {
                    invoiceHtml.Append("<td style='padding:10px; color:grey; border-bottom: dashed 1px #D1D1D1;'>");
                }
                else
                {
                    invoiceHtml.Append("<td style='padding:10px; color:grey; border-bottom: solid 2px black;'>");
                }

                invoiceHtml.Append(descriptionCopy);
                invoiceHtml.Append("</td>");

                //invoiceHtml.Append("<td style='color:grey'>"); ;
                //invoiceHtml.Append(lineItem.Quantity);
                //invoiceHtml.Append("</td>");

                if (!lineItem.Equals(last))
                {
                    invoiceHtml.Append("<td style='padding:10px; color:grey; border-bottom: dashed 1px #D1D1D1; text-align:center'>");
                }
                else
                {
                    invoiceHtml.Append("<td style='padding:10px; color:grey; border-bottom: solid 2px black; text-align:center'>");
                }

                invoiceHtml.Append(lineItemAmount);
                invoiceHtml.Append("</td>");

                invoiceHtml.Append("</tr>");
            }



            //--------------------
            invoiceHtml.Append("<tr>");

            //invoiceHtml.Append("<td>");
            //invoiceHtml.Append("");
            //invoiceHtml.Append("</td>");

            invoiceHtml.Append("<td style='text-align:right'>");
            invoiceHtml.Append("Subtotal:");
            invoiceHtml.Append("</td>");

            invoiceHtml.Append("<td style='padding:6px; text-align:center'>");
            invoiceHtml.Append(invoiceSubtotal);
            invoiceHtml.Append("</td>");

            invoiceHtml.Append("</tr>");

            //--------------------
            invoiceHtml.Append("<tr>");

            //invoiceHtml.Append("<td>");
            //invoiceHtml.Append("");
            //invoiceHtml.Append("</td>");

            invoiceHtml.Append("<td style='text-align:right'>");
            invoiceHtml.Append("Total:");
            invoiceHtml.Append("</td>");

            invoiceHtml.Append("<td style='padding:6px; text-align:center'>");
            invoiceHtml.Append(invoiceTotal);
            invoiceHtml.Append("</td>");

            invoiceHtml.Append("</tr>");

            //--------------------
            invoiceHtml.Append("<tr>");

            //invoiceHtml.Append("<td>");
            //invoiceHtml.Append("");
            //invoiceHtml.Append("</td>");

            invoiceHtml.Append("<td style='text-align:right'>");
            invoiceHtml.Append("<strong>Amount Due:</strong>");
            invoiceHtml.Append("</td>");

            invoiceHtml.Append("<td style='padding:8px; text-align:center; font-size:15px'><strong>");
            invoiceHtml.Append(invoiceAmountDue);
            invoiceHtml.Append("</strong></td>");

            invoiceHtml.Append("</tr>");


            //------------------
            invoiceHtml.Append("<table>");

            #endregion

            return(invoiceHtml.ToString());
        }
예제 #23
0
        public void TestTransferPaid()
        {
            var transfer = new StripeTransfer
            {
                Id     = "tx9876",
                Amount = 1443
            };

            var e = new StripeEvent
            {
                LiveMode = true,
                Type     = "transfer.paid",
                Created  = DateTime.Now.AddDays(-1),
                Data     = new StripeEventData
                {
                    Object = JObject.FromObject(transfer)
                }
            };

            var paymentmetadata = new Dictionary <string, object> {
                { "crossroads_transaction_type", "payment" }
            };
            var donationmetadata = new Dictionary <string, object> {
                { "crossroads_transaction_type", "donation" }
            };

            var dateCreated = DateTime.Now;
            var charges     = new List <StripeCharge>
            {
                new StripeCharge
                {
                    Id       = "ch111",
                    Amount   = 111,
                    Fee      = 1,
                    Type     = "charge",
                    Created  = dateCreated.AddDays(1),
                    Metadata = paymentmetadata
                },
                new StripeCharge
                {
                    Id       = "ch222",
                    Amount   = 222,
                    Fee      = 2,
                    Type     = "charge",
                    Created  = dateCreated.AddDays(2),
                    Metadata = paymentmetadata
                },
                new StripeCharge
                {
                    Id       = "ch333",
                    Amount   = 333,
                    Fee      = 3,
                    Type     = "charge",
                    Created  = dateCreated.AddDays(3),
                    Metadata = donationmetadata
                },
                new StripeCharge
                {
                    Id       = "ch777",
                    Amount   = 777,
                    Fee      = 7,
                    Type     = "charge",
                    Created  = dateCreated.AddDays(4),
                    Metadata = donationmetadata
                },
                new StripeCharge
                {
                    Id       = "ch888",
                    Amount   = 888,
                    Fee      = 8,
                    Type     = "charge",
                    Created  = dateCreated.AddDays(5),
                    Metadata = donationmetadata
                },
                new StripeCharge
                {
                    Id       = "re999",
                    Amount   = 999,
                    Fee      = 9,
                    Type     = "payment_refund",
                    Created  = dateCreated.AddDays(8),
                    Metadata = donationmetadata
                },
                new StripeCharge
                {
                    Id       = "ch444",
                    Amount   = 444,
                    Fee      = 4,
                    Type     = "charge",
                    Created  = dateCreated.AddDays(6),
                    Metadata = donationmetadata
                },
                new StripeCharge
                {
                    Id       = "ch555",
                    Amount   = 555,
                    Fee      = 5,
                    Type     = "refund",
                    Created  = dateCreated.AddDays(7),
                    Metadata = donationmetadata
                }
            };


            _paymentService.Setup(mocked => mocked.GetPaymentByTransactionCode("ch111")).Returns(new PaymentDTO
            {
                PaymentId = 1111,
                BatchId   = null,
                Status    = DonationStatus.Pending
            });

            _paymentService.Setup(mocked => mocked.GetPaymentByTransactionCode("ch222")).Returns(new PaymentDTO
            {
                PaymentId = 2222,
                BatchId   = null,
                Status    = DonationStatus.Pending
            });

            _donationService.Setup(mocked => mocked.GetDonationByProcessorPaymentId("ch333")).Returns(new DonationDTO
            {
                Id      = "3333",
                BatchId = null,
                Status  = DonationStatus.Pending
            });

            _donationService.Setup(mocked => mocked.GetDonationByProcessorPaymentId("ch444")).Throws(new Exception("Not gonna do it, wouldn't be prudent."));

            _paymentProcessorService.Setup(mocked => mocked.GetChargeRefund("ch555")).Returns(new StripeRefund
            {
                Data = new List <StripeRefundData>
                {
                    new StripeRefundData()
                    {
                        Id     = "ch555",
                        Amount = "987",
                        Charge = new StripeCharge {
                            Id = "re_123456"
                        }
                    }
                }
            });

            _donationService.Setup(mocked => mocked.GetDonationByProcessorPaymentId("ch555")).Returns(new DonationDTO
            {
                Id      = "5555",
                BatchId = 1984
            });
            _donationService.Setup(mocked => mocked.GetDonationBatch(1984)).Returns(new DonationBatchDTO
            {
                Id = 5150,
                ProcessorTransferId = "OU812"
            });

            var stripeRefundData = new StripeRefundData
            {
                Id       = "re999",
                Amount   = "999",
                ChargeId = "ch999",
                Charge   = new StripeCharge
                {
                    Id = "ch999"
                },
                BalanceTransaction = new StripeBalanceTransaction
                {
                    Created = DateTime.Now
                }
            };
            var refund = new StripeRefund
            {
                Data = new List <StripeRefundData>
                {
                    stripeRefundData
                }
            };

            _paymentProcessorService.Setup(mocked => mocked.GetRefund("re999")).Returns(stripeRefundData);

            _donationService.Setup(
                mocked => mocked.CreateDonationForBankAccountErrorRefund(It.Is <StripeRefund>(r => r.Data != null && r.Data.Count == 1 && r.Data[0].Equals(stripeRefundData))))
            .Returns(876);

            var firstRefund = true;

            _donationService.Setup(mocked => mocked.GetDonationByProcessorPaymentId("re999")).Returns(() =>
            {
                if (firstRefund)
                {
                    firstRefund = false;
                    throw (new DonationNotFoundException("re999"));
                }

                return(new DonationDTO()
                {
                    Id = "9999",
                    BatchId = null,
                    Amount = 999
                });
            });

            _donationService.Setup(mocked => mocked.GetDonationByProcessorPaymentId("ch777")).Returns(new DonationDTO
            {
                Id      = "7777",
                BatchId = 2112
            });

            _donationService.Setup(mocked => mocked.GetDonationBatch(2112)).Returns(new DonationBatchDTO
            {
                Id = 2112,
                ProcessorTransferId = null
            });

            var first = true;

            _donationService.Setup(mocked => mocked.GetDonationByProcessorPaymentId("ch888")).Returns(() =>
            {
                if (first)
                {
                    first = false;
                    throw (new DonationNotFoundException("ch888"));
                }

                return(new DonationDTO()
                {
                    Id = "8888",
                    BatchId = null,
                    Amount = 888,
                    Status = DonationStatus.Declined
                });
            });

            _donationService.Setup(mocked => mocked.UpdateDonationStatus(refund.Data[0].ChargeId, 777, refund.Data[0].BalanceTransaction.Created, null)).Returns(9999);

            var invoice = new StripeInvoice
            {
                Amount = 100,
                Id     = "in_888"
            };

            _paymentProcessorService.Setup(mocked => mocked.GetCharge("ch888")).Returns(new StripeCharge
            {
                Source = new StripeSource
                {
                    Object = "bank_account"
                },
                Invoice = invoice
            });

            _donationService.Setup(mocked => mocked.CreateDonationForInvoice(invoice)).Returns(88);

            _paymentProcessorService.Setup(mocked => mocked.GetChargesForTransfer("tx9876")).Returns(charges);
            _donationService.Setup(mocked => mocked.GetDepositByProcessorTransferId("tx9876")).Returns((DepositDTO)null);

            _donationService.Setup(
                mocked => mocked.CreatePaymentProcessorEventError(e, It.IsAny <StripeEventResponseDTO>()));
            _paymentService.Setup(mocked => mocked.UpdatePaymentStatus(1111, 999, e.Created, null)).Returns(1111);
            _paymentService.Setup(mocked => mocked.UpdatePaymentStatus(2222, 999, e.Created, null)).Returns(2222);
            _donationService.Setup(mocked => mocked.UpdateDonationStatus(3333, 999, e.Created, null)).Returns(3333);
            _donationService.Setup(mocked => mocked.UpdateDonationStatus(7777, 999, e.Created, null)).Returns(7777);
            _donationService.Setup(mocked => mocked.UpdateDonationStatus(9999, 999, e.Created, null)).Returns(9999);
            _donationService.Setup(mocked => mocked.CreateDeposit(It.IsAny <DepositDTO>())).Returns(
                (DepositDTO o) =>
            {
                o.Id = 98765;
                return(o);
            });
            _donationService.Setup(mocked => mocked.CreateDonationBatch(It.IsAny <DonationBatchDTO>())).Returns((DonationBatchDTO o) => o);
            _paymentService.Setup(mocked => mocked.CreatePaymentBatch(It.IsAny <DonationBatchDTO>())).Returns((DonationBatchDTO o) => o);

            var result = _fixture.ProcessStripeEvent(e);

            Assert.IsNotNull(result);
            Assert.IsInstanceOf <TransferPaidResponseDTO>(result);
            var tp = (TransferPaidResponseDTO)result;

            Assert.AreEqual(8, tp.TotalTransactionCount);
            Assert.AreEqual(6, tp.SuccessfulUpdates.Count);
            Assert.AreEqual(charges.Take(6).Select(charge => charge.Id), tp.SuccessfulUpdates);
            Assert.AreEqual(2, tp.FailedUpdates.Count);
            Assert.AreEqual("ch555", tp.FailedUpdates[1].Key);
            Assert.AreEqual("ch444", tp.FailedUpdates[0].Key);
            Assert.AreEqual("Not gonna do it, wouldn't be prudent.", tp.FailedUpdates[0].Value);
            Assert.IsNotNull(tp.Batch);
            Assert.IsNotNull(tp.Deposit);
            Assert.IsNotNull(tp.Exception);

            _donationService.Verify(mocked => mocked.CreateDonationBatch(It.Is <DonationBatchDTO>(o =>
                                                                                                  o.BatchName.Matches(@"MP\d{12}D") &&
                                                                                                  o.SetupDateTime == o.FinalizedDateTime &&
                                                                                                  o.BatchEntryType == 555 &&
                                                                                                  o.ItemCount == 4 &&
                                                                                                  o.BatchTotalAmount == ((333 + 777 + 888 + 999) / Constants.StripeDecimalConversionValue) &&
                                                                                                  o.Donations != null &&
                                                                                                  o.Donations.Count == 4 &&
                                                                                                  o.DepositId == 98765 &&
                                                                                                  o.ProcessorTransferId.Equals("tx9876")
                                                                                                  )));

            _donationService.Verify(mocked => mocked.CreateDeposit(It.Is <DepositDTO>(o =>
                                                                                      o.DepositName.Matches(@"MP\d{12}") &&
                                                                                      !o.Exported &&
                                                                                      o.AccountNumber.Equals(" ") &&
                                                                                      o.BatchCount == 2 &&
                                                                                      o.DepositDateTime != null &&
                                                                                      o.DepositTotalAmount == ((transfer.Amount + 30) / Constants.StripeDecimalConversionValue) &&
                                                                                      o.ProcessorFeeTotal == (30 / Constants.StripeDecimalConversionValue) &&
                                                                                      o.DepositAmount == (transfer.Amount / Constants.StripeDecimalConversionValue) &&
                                                                                      o.Notes == null &&
                                                                                      o.ProcessorTransferId.Equals("tx9876")
                                                                                      )));

            _paymentProcessorService.VerifyAll();
            _donationService.VerifyAll();
        }
        public IHttpActionResult GetInvoice(string id)
        {
            if (!Settings.Current.EnableBilling)
            {
                return(NotFound());
            }

            if (!id.StartsWith("in_"))
            {
                id = "in_" + id;
            }

            StripeInvoice stripeInvoice = null;

            try {
                var invoiceService = new StripeInvoiceService();
                stripeInvoice = invoiceService.Get(id);
            } catch (Exception ex) {
                Log.Error().Exception(ex).Message("An error occurred while getting the invoice: " + id).Write();
            }

            if (stripeInvoice == null || String.IsNullOrEmpty(stripeInvoice.CustomerId))
            {
                return(NotFound());
            }

            var organization = _repository.GetByStripeCustomerId(stripeInvoice.CustomerId);

            if (organization == null || !IsInOrganization(organization.Id))
            {
                return(NotFound());
            }

            var invoice = new Invoice {
                Id               = stripeInvoice.Id.Substring(3),
                OrganizationId   = organization.Id,
                OrganizationName = organization.Name,
                Date             = stripeInvoice.Date.GetValueOrDefault(),
                Paid             = stripeInvoice.Paid,
                Total            = stripeInvoice.Total / 100.0
            };

            foreach (var line in stripeInvoice.StripeInvoiceLineItems.Data)
            {
                var item = new InvoiceLineItem {
                    Amount = line.Amount / 100.0
                };

                if (line.Plan != null)
                {
                    item.Description = String.Format("Exceptionless - {0} Plan ({1}/{2})", line.Plan.Name, (line.Plan.Amount / 100.0).ToString("c"), line.Plan.Interval);
                }
                else
                {
                    item.Description = line.Description;
                }

                if (stripeInvoice.PeriodStart == stripeInvoice.PeriodEnd)
                {
                    item.Date = stripeInvoice.PeriodStart.ToShortDateString();
                }
                else
                {
                    item.Date = String.Format("{0} - {1}", stripeInvoice.PeriodStart.ToShortDateString(), stripeInvoice.PeriodEnd.ToShortDateString());
                }

                invoice.Items.Add(item);
            }

            var coupon = stripeInvoice.StripeDiscount != null ? stripeInvoice.StripeDiscount.StripeCoupon : null;

            if (coupon != null)
            {
                double discountAmount = coupon.AmountOff ?? stripeInvoice.Subtotal * (coupon.PercentOff.GetValueOrDefault() / 100.0);
                string description    = String.Format("{0} {1}", coupon.Id, coupon.PercentOff.HasValue ? String.Format("({0}% off)", coupon.PercentOff.Value) : String.Format("({0} off)", (coupon.AmountOff.GetValueOrDefault() / 100.0).ToString("C")));

                invoice.Items.Add(new InvoiceLineItem {
                    Description = description, Amount = discountAmount
                });
            }

            return(Ok(invoice));
        }
예제 #25
0
 public void InvoicePaymentSucceeded(DateTime?eventTimestamp, StripeInvoice invoice)
 {
     _logger.Debug($"Processing invoice.payment_succeeded event for subscription id {invoice.Subscription}");
     _donationService.CreateDonationForInvoice(invoice);
 }
예제 #26
0
        public async Task <IHttpActionResult> GetInvoiceAsync(string id)
        {
            if (!Settings.Current.EnableBilling)
            {
                return(NotFound());
            }

            if (!id.StartsWith("in_"))
            {
                id = "in_" + id;
            }

            StripeInvoice stripeInvoice = null;

            try {
                var invoiceService = new StripeInvoiceService(Settings.Current.StripeApiKey);
                stripeInvoice = await invoiceService.GetAsync(id);
            } catch (Exception ex) {
                _logger.Error().Exception(ex).Message("An error occurred while getting the invoice: " + id).Identity(CurrentUser.EmailAddress).Property("User", CurrentUser).SetActionContext(ActionContext).Write();
            }

            if (String.IsNullOrEmpty(stripeInvoice?.CustomerId))
            {
                return(NotFound());
            }

            var organization = await _repository.GetByStripeCustomerIdAsync(stripeInvoice.CustomerId);

            if (organization == null || !CanAccessOrganization(organization.Id))
            {
                return(NotFound());
            }

            var invoice = new Invoice {
                Id               = stripeInvoice.Id.Substring(3),
                OrganizationId   = organization.Id,
                OrganizationName = organization.Name,
                Date             = stripeInvoice.Date.GetValueOrDefault(),
                Paid             = stripeInvoice.Paid,
                Total            = stripeInvoice.Total / 100.0
            };

            foreach (var line in stripeInvoice.StripeInvoiceLineItems.Data)
            {
                var item = new InvoiceLineItem {
                    Amount = line.Amount / 100.0
                };

                if (line.Plan != null)
                {
                    item.Description = $"Exceptionless - {line.Plan.Name} Plan ({(line.Plan.Amount / 100.0):c}/{line.Plan.Interval})";
                }
                else
                {
                    item.Description = line.Description;
                }

                item.Date = $"{(line.StripePeriod.Start ?? stripeInvoice.PeriodStart).ToShortDateString()} - {(line.StripePeriod.End ?? stripeInvoice.PeriodEnd).ToShortDateString()}";
                invoice.Items.Add(item);
            }

            var coupon = stripeInvoice.StripeDiscount?.StripeCoupon;

            if (coupon != null)
            {
                if (coupon.AmountOff.HasValue)
                {
                    double discountAmount = coupon.AmountOff.GetValueOrDefault() / 100.0;
                    string description    = $"{coupon.Id} ({discountAmount.ToString("C")} off)";
                    invoice.Items.Add(new InvoiceLineItem {
                        Description = description, Amount = discountAmount
                    });
                }
                else
                {
                    double discountAmount = (stripeInvoice.Subtotal / 100.0) * (coupon.PercentOff.GetValueOrDefault() / 100.0);
                    string description    = $"{coupon.Id} ({coupon.PercentOff.GetValueOrDefault()}% off)";
                    invoice.Items.Add(new InvoiceLineItem {
                        Description = description, Amount = discountAmount
                    });
                }
            }

            return(Ok(invoice));
        }
        public async Task <ActionResult <Invoice> > GetInvoiceAsync(string id)
        {
            if (!_stripeOptions.Value.EnableBilling)
            {
                return(NotFound());
            }

            if (!id.StartsWith("in_"))
            {
                id = "in_" + id;
            }

            StripeInvoice stripeInvoice = null;

            try {
                var invoiceService = new StripeInvoiceService(_stripeOptions.Value.StripeApiKey);
                stripeInvoice = await invoiceService.GetAsync(id);
            } catch (Exception ex) {
                using (_logger.BeginScope(new ExceptionlessState().Tag("Invoice").Identity(CurrentUser.EmailAddress).Property("User", CurrentUser).SetHttpContext(HttpContext)))
                    _logger.LogError(ex, "An error occurred while getting the invoice: {InvoiceId}", id);
            }

            if (String.IsNullOrEmpty(stripeInvoice?.CustomerId))
            {
                return(NotFound());
            }

            var organization = await _repository.GetByStripeCustomerIdAsync(stripeInvoice.CustomerId);

            if (organization == null || !CanAccessOrganization(organization.Id))
            {
                return(NotFound());
            }

            var invoice = new Invoice {
                Id               = stripeInvoice.Id.Substring(3),
                OrganizationId   = organization.Id,
                OrganizationName = organization.Name,
                Date             = stripeInvoice.Date.GetValueOrDefault(),
                Paid             = stripeInvoice.Paid,
                Total            = stripeInvoice.Total / 100.0m
            };

            foreach (var line in stripeInvoice.StripeInvoiceLineItems.Data)
            {
                var item = new InvoiceLineItem {
                    Amount = line.Amount / 100.0m
                };

                if (line.Plan != null)
                {
                    string planName = line.Plan.Nickname ?? _billingManager.GetBillingPlan(line.Plan.Id)?.Name;
                    item.Description = $"Exceptionless - {planName} Plan ({(line.Plan.Amount / 100.0):c}/{line.Plan.Interval})";
                }
                else
                {
                    item.Description = line.Description;
                }

                item.Date = $"{(line.StripePeriod.Start ?? stripeInvoice.PeriodStart).ToShortDateString()} - {(line.StripePeriod.End ?? stripeInvoice.PeriodEnd).ToShortDateString()}";
                invoice.Items.Add(item);
            }

            var coupon = stripeInvoice.StripeDiscount?.StripeCoupon;

            if (coupon != null)
            {
                if (coupon.AmountOff.HasValue)
                {
                    decimal discountAmount = coupon.AmountOff.GetValueOrDefault() / 100.0m;
                    string  description    = $"{coupon.Id} ({discountAmount.ToString("C")} off)";
                    invoice.Items.Add(new InvoiceLineItem {
                        Description = description, Amount = discountAmount
                    });
                }
                else
                {
                    decimal discountAmount = (stripeInvoice.Subtotal / 100.0m) * (coupon.PercentOff.GetValueOrDefault() / 100.0m);
                    string  description    = $"{coupon.Id} ({coupon.PercentOff.GetValueOrDefault()}% off)";
                    invoice.Items.Add(new InvoiceLineItem {
                        Description = description, Amount = discountAmount
                    });
                }
            }

            return(Ok(invoice));
        }