From beb046360f4ffadea5a771bd1669b32c4c8afcf9 Mon Sep 17 00:00:00 2001 From: Evan Snyder Date: Mon, 2 Mar 2026 16:01:57 -0500 Subject: [PATCH] Added SendInvoice feature --- QuickBooksSharp.Tests/DataServiceTests.cs | 11 ++++++++++ .../Infrastructure/IQuickBooksHttpClient.cs | 1 + .../Infrastructure/QuickBooksHttpClient.cs | 6 ++++++ QuickBooksSharp/Services/DataService.cs | 21 +++++++++++++++++++ QuickBooksSharp/Services/IDataService.cs | 10 +++++++++ 5 files changed, 49 insertions(+) diff --git a/QuickBooksSharp.Tests/DataServiceTests.cs b/QuickBooksSharp.Tests/DataServiceTests.cs index 638feff..31cb5ff 100644 --- a/QuickBooksSharp.Tests/DataServiceTests.cs +++ b/QuickBooksSharp.Tests/DataServiceTests.cs @@ -500,6 +500,17 @@ public async Task CreatePaymentAndVoidAsync() Assert.IsNotNull(voidPaymentResponse.Response); } + [TestMethod] + public async Task SendInvoiceTest() + { + var response = await _service.QueryAsync("SELECT * FROM Invoice MAXRESULTS 1"); + + Assert.IsTrue(response.Response!.Entities!.Length > 0); + + var sentInvoice = await _service.SendInvoice(response.Response!.Entities![0].Id!); + Assert.IsTrue(sentInvoice.Response.EmailStatus == EmailStatusEnum.EmailSent); + } + [TestMethod] public async Task CreateTaxCodeAndRateAsync() { diff --git a/QuickBooksSharp/Infrastructure/IQuickBooksHttpClient.cs b/QuickBooksSharp/Infrastructure/IQuickBooksHttpClient.cs index b2f9c20..5c2ac45 100644 --- a/QuickBooksSharp/Infrastructure/IQuickBooksHttpClient.cs +++ b/QuickBooksSharp/Infrastructure/IQuickBooksHttpClient.cs @@ -9,6 +9,7 @@ public interface IQuickBooksHttpClient { Task GetAsync(Url url); Task PostAsync(Url url, object content); + Task PostAsync(Url url); Task SendAsync(Func makeRequest); Task SendAsync(Func makeRequest); } diff --git a/QuickBooksSharp/Infrastructure/QuickBooksHttpClient.cs b/QuickBooksSharp/Infrastructure/QuickBooksHttpClient.cs index 1478e4c..49502b2 100644 --- a/QuickBooksSharp/Infrastructure/QuickBooksHttpClient.cs +++ b/QuickBooksSharp/Infrastructure/QuickBooksHttpClient.cs @@ -65,6 +65,12 @@ public async Task PostAsync(Url url, object content) return await this.SendAsync(makeRequest); } + public async Task PostAsync(Url url) + { + Func makeRequest = () => new HttpRequestMessage(HttpMethod.Post, url); + return await this.SendAsync(makeRequest); + } + public async Task SendAsync(Func makeRequest) { var response = await this.SendAsync(makeRequest); diff --git a/QuickBooksSharp/Services/DataService.cs b/QuickBooksSharp/Services/DataService.cs index 2cdb8f6..f14734d 100644 --- a/QuickBooksSharp/Services/DataService.cs +++ b/QuickBooksSharp/Services/DataService.cs @@ -166,6 +166,27 @@ private async Task PostWithEntityResultAsync(TEntity e) return await _client.PostAsync(url, e); } + public async Task> SendInvoice(string invoiceId, string? sendTo = null) + { + var url = new Url(_serviceUrl).AppendPathSegment($"invoice/{invoiceId}/send"); + + if (!string.IsNullOrEmpty(sendTo)) + { + url = url.SetQueryParam("sendTo", sendTo); + } + + var res = await _client.PostAsync(url); + return new IntuitResponse + { + RequestId = res.requestId, + Time = res.time, + Status = res.status, + Warnings = res.Warnings, + Fault = res.Fault, + Response = (Invoice?)res.IntuitObject + }; + } + /// /// Unlike other entities, TaxService is a special case where the return type is not an IntuitResponse but the entity itself. /// diff --git a/QuickBooksSharp/Services/IDataService.cs b/QuickBooksSharp/Services/IDataService.cs index c5d4c58..da8a5a0 100644 --- a/QuickBooksSharp/Services/IDataService.cs +++ b/QuickBooksSharp/Services/IDataService.cs @@ -34,6 +34,16 @@ public interface IDataService /// Unique identifier for this object /// This resource returns the specified object in the response body as an Adobe Portable Document Format (PDF) file. The resulting PDF file is formatted according to custom form styles in the company settings. Task GetInvoicePDFAsync(string invoiceId); + + /// + /// Sends an invoice to a customer or vendor. This will update the Invoice.EmailStatus to EmailSent and Invoice.DeliveryInfo + /// will be populated with the sending information. + /// + /// Id of the invoice to send + /// Email address to send the invoice to. Optional. If not provided, the Invoice.BillEmail address will be used. + /// If provided, this will replace the Invoice.BillEmail with this value + /// The updated invoice after sending information + Task> SendInvoice(string invoiceId, string? sendTo = null); Task PostTaxServiceAsync(TaxService taxService); }