/// <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 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); }
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)); }
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)); }
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); }
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 }