/// <summary>
 /// Removes one InvoiceLineItem from this Invoice.
 /// </summary>
 /// <param name="lineItem">The InvoiceLineItem to remove from the Invoice.</param>
 public void RemoveLineItem(InvoiceLineItem lineItem)
 {
     _invoice.LineItems.Remove(lineItem);
 }
Exemple #2
0
        public async Task CreateTransactionFile_WithTwoMemberUploadsForTheSameScheme_CreatesFileWithOneInvoiceWithTwoLineItems()
        {
            // Arrange
            UKCompetentAuthority authority = A.Dummy <UKCompetentAuthority>();

            Organisation organisation = Organisation.CreateSoleTrader("Test organisation");

            Scheme scheme = new Scheme(organisation);

            scheme.UpdateScheme(
                "Test scheme",
                "WEE/AA1111AA/SCH",
                "WEE00000001",
                A.Dummy <ObligationType>(),
                authority);

            int complianceYear = A.Dummy <int>();

            MemberUpload memberUpload1 = new MemberUpload(
                A.Dummy <Guid>(),
                A.Dummy <string>(),
                A.Dummy <List <MemberUploadError> >(),
                100,
                complianceYear,
                scheme,
                A.Dummy <string>(),
                A.Dummy <string>(),
                false);

            memberUpload1.Submit(A.Dummy <User>());

            MemberUpload memberUpload2 = new MemberUpload(
                A.Dummy <Guid>(),
                A.Dummy <string>(),
                A.Dummy <List <MemberUploadError> >(),
                200,
                complianceYear,
                scheme,
                A.Dummy <string>(),
                A.Dummy <string>(),
                false);

            memberUpload2.Submit(A.Dummy <User>());

            List <MemberUpload> memberUploads = new List <MemberUpload>();

            memberUploads.Add(memberUpload1);
            memberUploads.Add(memberUpload2);

            InvoiceRun invoiceRun = new InvoiceRun(authority, memberUploads, A.Dummy <User>());

            A.CallTo(() => transactionReferenceGenerator.GetNextTransactionReferenceAsync()).Returns("WEE800001H");

            // Act
            var result = await generator.CreateAsync(0, invoiceRun);

            TransactionFile transactionFile = result.IbisFile;

            // Assert
            Assert.NotNull(transactionFile);
            Assert.Equal(1, transactionFile.Invoices.Count);

            Invoice invoice = transactionFile.Invoices[0];

            Assert.NotNull(invoice);

            Assert.Equal(300, invoice.TransactionTotal);

            Assert.NotNull(invoice.LineItems);
            Assert.Equal(2, invoice.LineItems.Count);

            InvoiceLineItem lineItem1 = invoice.LineItems[0];

            Assert.NotNull(lineItem1);
            Assert.Equal(100, lineItem1.AmountExcludingVAT);

            InvoiceLineItem lineItem2 = invoice.LineItems[1];

            Assert.NotNull(lineItem2);
            Assert.Equal(200, lineItem2.AmountExcludingVAT);
        }
 /// <summary>
 /// Adds an InvoiceLineItem to this Invoice.
 /// </summary>
 /// <param name="lineItem">The InvoiceLineItem to add to this Invoice.</param>
 public void AddLineItem(InvoiceLineItem lineItem)
 {
     _invoice.LineItems.Add(lineItem);
 }
 /// <summary>
 /// Removes one InvoiceLineItem from this Invoice.
 /// </summary>
 /// <param name="lineItem">The InvoiceLineItem to remove from the Invoice.</param>
 public void RemoveLineItem(InvoiceLineItem lineItem)
 {
     _invoice.LineItems.Remove(lineItem);
 }
        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 = invoiceService.Get(id);
            } catch (Exception ex) {
                _logger.Error().Exception(ex).Message("An error occurred while getting the invoice: " + id).Identity(ExceptionlessUser.EmailAddress).Property("User", ExceptionlessUser).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).ToString("c")}/{line.Plan.Interval})";
                }
                else
                {
                    item.Description = line.Description;
                }

                if (stripeInvoice.PeriodStart == stripeInvoice.PeriodEnd)
                {
                    item.Date = stripeInvoice.PeriodStart.ToShortDateString();
                }
                else
                {
                    item.Date = $"{stripeInvoice.PeriodStart.ToShortDateString()} - {stripeInvoice.PeriodEnd.ToShortDateString()}";
                }

                invoice.Items.Add(item);
            }

            var coupon = stripeInvoice.StripeDiscount?.StripeCoupon;

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

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

            return(Ok(invoice));
        }
Exemple #6
0
        public async Task <ActionResult <Invoice> > 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) {
                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));
        }
 /// <summary>
 /// Adds an InvoiceLineItem to this Invoice.
 /// </summary>
 /// <param name="lineItem">The InvoiceLineItem to add to this Invoice.</param>
 public void AddLineItem(InvoiceLineItem lineItem)
 {
     _invoice.LineItems.Add(lineItem);
 }
Exemple #8
0
        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));
        }
        public async Task CreateTransactionFile_WithOneMemberUpload_CreatesOneInvoiceWithOneLineItem()
        {
            // Arrange
            UKCompetentAuthority authority = A.Dummy <UKCompetentAuthority>();

            Organisation organisation = Organisation.CreateSoleTrader("Test organisation");

            Scheme scheme = new Scheme(organisation);

            scheme.UpdateScheme(
                "Test scheme",
                "WEE/AA1111AA/SCH",
                "WEE00000001",
                A.Dummy <ObligationType>(),
                authority);

            int complianceYear = A.Dummy <int>();

            MemberUpload memberUpload = new MemberUpload(
                A.Dummy <Guid>(),
                A.Dummy <string>(),
                A.Dummy <List <MemberUploadError> >(),
                123.45m,
                complianceYear,
                scheme,
                A.Dummy <string>(),
                A.Dummy <string>(),
                false);

            SystemTime.Freeze(new DateTime(2015, 1, 1));
            memberUpload.Submit(A.Dummy <User>());
            SystemTime.Unfreeze();

            List <MemberUpload> memberUploads = new List <MemberUpload>();

            memberUploads.Add(memberUpload);

            ITransactionReferenceGenerator transactionReferenceGenerator = A.Fake <ITransactionReferenceGenerator>();

            A.CallTo(() => transactionReferenceGenerator.GetNextTransactionReferenceAsync()).Returns("WEE800001H");

            BySubmissionTransactionFileGenerator generator = new BySubmissionTransactionFileGenerator(transactionReferenceGenerator);

            SystemTime.Freeze(new DateTime(2015, 12, 31));
            InvoiceRun invoiceRun = new InvoiceRun(authority, memberUploads, A.Dummy <User>());

            SystemTime.Unfreeze();

            // Act
            var result = await generator.CreateAsync(0, invoiceRun);

            TransactionFile transactionFile = result.IbisFile;

            // Assert
            Assert.NotNull(transactionFile);
            Assert.Equal(1, transactionFile.Invoices.Count);

            Invoice invoice = transactionFile.Invoices[0];

            Assert.NotNull(invoice);

            Assert.Equal(TransactionType.Invoice, invoice.TransactionType);
            Assert.Equal("WEE800001H", invoice.TransactionReference);
            Assert.Equal(123.45m, invoice.TransactionTotal);
            Assert.Equal(null, invoice.TransactionHeaderNarrative);
            Assert.Equal(new DateTime(2015, 12, 31), invoice.TransactionDate);
            Assert.Equal(null, invoice.RelatedTransactionReference);
            Assert.Equal(CurrencyCode.GBP, invoice.CurrencyCode);
            Assert.Equal("WEE00000001", invoice.CustomerReference);

            Assert.NotNull(invoice.LineItems);
            Assert.Equal(1, invoice.LineItems.Count);

            InvoiceLineItem lineItem = invoice.LineItems[0];

            Assert.NotNull(lineItem);

            Assert.Equal(123.45m, lineItem.AmountExcludingVAT);
            Assert.Equal("Charge for producer registration submission made on 01 Jan 2015.", lineItem.Description);
            Assert.Equal("H", lineItem.AreaCode);
            Assert.Equal("H", lineItem.ContextCode);
            Assert.Equal("W", lineItem.IncomeStreamCode);
            Assert.Equal((ulong)1, lineItem.Quantity);
            Assert.Equal(UnitOfMeasure.Each, lineItem.UnitOfMeasure);
            Assert.Equal(null, lineItem.VatCode);
        }
 public static InvoiceLineItem CreateInvoiceLineItem(long invoiceLineItemID)
 {
     InvoiceLineItem invoiceLineItem = new InvoiceLineItem();
     invoiceLineItem.InvoiceLineItemID = invoiceLineItemID;
     return invoiceLineItem;
 }
 public void AddToInvoiceLineItem(InvoiceLineItem invoiceLineItem)
 {
     base.AddObject("InvoiceLineItem", invoiceLineItem);
 }
Exemple #12
0
        public void Can_Create_A_Customer_Invoice_And_Order()
        {
            // Adding the shipmethod is typically done in the back office through the UI.
            // Interested in the use case to dynamically add theses?
            var key = Constants.ProviderKeys.Shipping.FixedRateShippingProviderKey;
            var defaultCatalogKey = Constants.DefaultKeys.Warehouse.DefaultWarehouseCatalogKey;

            // this would have to be done through the back office as it uses an internal service
            var us        = MerchelloContext.Current.Services.StoreSettingService.GetCountryByCode("US");
            var usCountry = new ShipCountry(defaultCatalogKey, us);

            ((ServiceContext)MerchelloContext.Current.Services).ShipCountryService.Save(usCountry);

            // we can use this later.
            var rateTableProvider = (FixedRateShippingGatewayProvider)MerchelloContext.Current.Gateways.Shipping.GetProviderByKey(key);

            // again usually done in the back office
            if (!rateTableProvider.ShipMethods.Any())
            {
                // creates the rate table for ship rate quotes
                var gwShipmeMethod = (FixedRateShippingGatewayMethod)rateTableProvider.CreateShipMethod(FixedRateShippingGatewayMethod.QuoteType.VaryByWeight, usCountry, "Ground (Vary by Weight)");
                gwShipmeMethod.RateTable.AddRow(0, 10, 5);
                gwShipmeMethod.RateTable.AddRow(10, 15, 10); // total weight should be 10M so we should hit this tier
                gwShipmeMethod.RateTable.AddRow(15, 25, 25);
                gwShipmeMethod.RateTable.AddRow(25, 10000, 100);
                rateTableProvider.SaveShippingGatewayMethod(gwShipmeMethod);
            }



            // Get the persisted customer
            const string loginName = "rusty";

            var customerService = MerchelloContext.Current.Services.CustomerService;

            var customer = customerService.GetByLoginName(loginName)
                           ?? customerService.CreateCustomerWithKey(loginName, "Rusty", "Swayne", "*****@*****.**");

            // I'll use this for billing and shipping
            var billingAddress = new Address()
            {
                Name        = "Mindfly Web Design Studio",
                Address1    = "114 W. Magnolia St. Suite 300",
                Locality    = "Bellingham",
                Region      = "WA",
                PostalCode  = "98225",
                CountryCode = "US"
            };



            // Most of the time this information is brought in from the IProductVariant - but the idea is you can
            // describe things on the fly
            var extendedData = new ExtendedDataCollection();

            // this is used to determine where a shipment originates
            extendedData.SetValue(Constants.ExtendedDataKeys.WarehouseCatalogKey, defaultCatalogKey.ToString());
            // items set to shippable
            extendedData.SetValue(Constants.ExtendedDataKeys.TrackInventory, "false");
            extendedData.SetValue(Constants.ExtendedDataKeys.Shippable, "true");
            extendedData.SetValue(Constants.ExtendedDataKeys.Weight, "1.25");
            extendedData.SetValue(Constants.ExtendedDataKeys.CurrencyCode, "USD");

            var item = new InvoiceLineItem(LineItemType.Product, "My product", "mySku", 2, 10M, extendedData);

            var invoiceService = MerchelloContext.Current.Services.InvoiceService;

            var invoice = invoiceService.CreateInvoice(Constants.DefaultKeys.InvoiceStatus.Unpaid);

            // I'd say we need to add a parameter to the service so we don't have to do this
            // http://issues.merchello.com/youtrack/issue/M-434
            ((Invoice)invoice).CustomerKey = customer.Key;

            // The version key is useful in some cases to invalidate shipping quotes or taxation calculations
            invoice.VersionKey = Guid.NewGuid();

            invoice.Items.Add(item);

            // at this point the invoice is not saved and we don't have an invoice number
            // however, we may want to quote shipping so we need a shipment

            // Shipment Statuses are new in 1.5.0
            var warehouse = MerchelloContext.Current.Services.WarehouseService.GetDefaultWarehouse();

            var shipmentStatus =
                MerchelloContext.Current.Services.ShipmentService.GetShipmentStatusByKey(
                    Constants.DefaultKeys.ShipmentStatus.Quoted);

            // since we know all the items in the invoice will be shipped we don't need to filter
            var shipment = new Shipment(shipmentStatus, warehouse.AsAddress(), billingAddress, invoice.Items);

            // since we already know the shipping provider we want from above we can do
            var quotes = rateTableProvider.QuoteShippingGatewayMethodsForShipment(shipment);

            // if we wanted Merchello to get quotes from all shipping providers we'd do the following
            // var quotes = shipment.ShipmentRateQuotes();

            if (quotes.Any())
            {
                // this check makes certain a quote was returned.  For example if the collection of items was outside the allowable
                // weight range, the provider would not return a quote.

                // Add the first quote to the invoice.

                invoice.Items.Add(quotes.FirstOrDefault().AsLineItemOf <InvoiceLineItem>());
            }

            // you do need to update the total ... this is usually done in the InvoiceBuilder in
            // instantiated by a SalesPreparation sub class
            var charges   = invoice.Items.Where(x => x.LineItemType != LineItemType.Discount).Sum(x => x.TotalPrice);
            var discounts = invoice.Items.Where(x => x.LineItemType == LineItemType.Discount).Sum(x => x.TotalPrice);

            // total the invoice
            decimal converted;

            invoice.Total = decimal.TryParse((charges - discounts).ToString(CultureInfo.InvariantCulture), NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture.NumberFormat, out converted) ? converted : 0;

            // Now we save the invoice since we have to have a real record of something to collect a payment against
            // This also generates the invoice number
            invoiceService.Save(invoice);

            Console.WriteLine(invoice.InvoiceNumber);

            // cash payment method
            var cashProvider = MerchelloContext.Current.Gateways.Payment.GetProviderByKey(Constants.ProviderKeys.Payment.CashPaymentProviderKey);

            if (cashProvider != null)
            {
                var cash = cashProvider.PaymentMethods.FirstOrDefault(); // default install has a single payment method "Cash"

                // I usually Authorize a cash payment if taken online since we don't really see the money.  Capture is used
                // when the money comes in.  In your inquiry, it looks like you are assuming the money is in hand at the
                // time of the purchase, so we'll use AuthorizeCapture straight away.

                var attempt = invoice.AuthorizeCapturePayment(cash.Key);

                if (!attempt.Payment.Success)
                {
                    // handle the error
                }

                // otherwise you'll notice
                var approved = attempt.ApproveOrderCreation; // equals true

                // the order will be automatically created by the event handler in Merchello.Core.Gateways.GatewayEvents

                // however in this test I don't have the event wired up so I have to do it manuall
                if (approved)
                {
                    var order = invoice.PrepareOrder();
                    MerchelloContext.Current.Services.OrderService.Save(order);

                    var items = order.Items;
                }
            }
            // Cash provider is not active
        }