QuickBooks API Create Invoice.

This example uses the Intuit API V3 SDK version 8.1.0 and the Microsoft MVC framework written in C#

The full working example can be downloaded from GitHub.

In the blog, I will now show you how to create a new invoice using QuickBooks API.

This blog is in two parts and this is part two.

If you do not know how to create a new customer using Intuits QuickBooks API, then please see the previous blog.

So let's get started, first let create the customer model, the code for that is below.

using System.ComponentModel.DataAnnotations;

namespace QuickBooksIntergration.Models.CustomerModel
{
    public class CustomerViewModel
    {
        [Display(Name = "Company Name")]
        public string CompanyName       { get; set; }
        public string DisplayName       { get; set; }
        [Display(Name = "Title")]
        public string Title             { get; set; }
        [Display(Name = "Surname")]
        public string FamilyName        { get; set; }
        [Display(Name = "First Name")]
        public string GivenName         { get; set; }
        [Display(Name = "Middle Name")]
        public string MiddleName        { get; set; }
        [Display(Name = "Address Line 1")]
        public string AddressLineOne    { get; set; }
        [Display(Name = "City")]
        public string City              { get; set; }
        [Display(Name = "County/Region")]
        public string County            { get; set; }
        [Display(Name = "Post-Code/Zip")]
        public string PostCode          { get; set; }
        [Display(Name = "Country")]
        public string Country           { get; set; }
        [Display(Name = "Email")]
        public string Email             { get; set; }
        [Display(Name = "Phone Number")]
        public string PhoneNumber       { get; set; }
    }
}

QuickBooks API is very powerful and the properties above are only a few of the fields you can use.

Next, create the invoice class, again the code for that is below.

using System;
using System.Collections.Generic;
using Intuit.Ipp.Data;

namespace QuickBooksIntergration.Models.CustomerInvoice
{
    public static class CreateInvoice
    {
        public static Invoice GetInvoice(Customer customer)
        {
            PhysicalAddress physicalAddress = new PhysicalAddress
            {
                Line1                   = customer.BillAddr.Line1,
                City                    = customer.BillAddr.City,
                CountrySubDivisionCode  = customer.BillAddr.CountrySubDivisionCode,
                PostalCode              = customer.BillAddr.PostalCode,
                Country                 = customer.BillAddr.Country
            };

            Invoice invoice = new Invoice
            {
                Deposit             = 0m,
                DepositSpecified    = true,

                CustomerRef = new ReferenceType
                {
                    name    = customer.DisplayName,
                    Value   = customer.Id
                },
                DueDate                         = DateTime.Now.AddDays(14).Date,
                DueDateSpecified                = true,
                TotalAmt                        = 3000m,
                TotalAmtSpecified               = true,
                ApplyTaxAfterDiscount           = false,
                ApplyTaxAfterDiscountSpecified  = true,
                PrintStatus                     = PrintStatusEnum.NotSet,
                PrintStatusSpecified            = true,
                EmailStatus                     = EmailStatusEnum.NeedToSend,
                EmailStatusSpecified            = true
            };

            EmailAddress billEmailAddress = new EmailAddress
            {
                Address             = customer.PrimaryEmailAddr.Address,
                Default             = true,
                DefaultSpecified    = true
            };

            invoice.BillEmail   = billEmailAddress;
            invoice.BillAddr    = physicalAddress;
            invoice.ShipAddr    = physicalAddress;

            invoice.Balance             = 3000m;
            invoice.BalanceSpecified    = true;

            invoice.TxnDate             = DateTime.Now.Date;
            invoice.TxnDateSpecified    = true;

            //Hard coded values, would really come from whatever system you are using to create sales item
            List lines = new List();
            Line line = new Line
            {
                Description         = "Consulation Service",
                Amount              = 3000m,
                AmountSpecified     = true,
                DetailType          = LineDetailTypeEnum.SalesItemLineDetail,
                DetailTypeSpecified = true
            };

            SalesItemLineDetail salesItemLineDetail = new SalesItemLineDetail
            {
                ItemElementName = ItemChoiceType.UnitPrice,

                Qty             = 1,
                QtySpecified    = true,

                TaxCodeRef = new ReferenceType
                {
                    Value = "TAX"
                },
                AnyIntuitObject = 3000m
            };

            line.AnyIntuitObject = salesItemLineDetail;

            lines.Add(line);

            invoice.Line = lines.ToArray();

            return invoice;
        }
    }
}

I have hardcoded the invoice values as these would come from whatever source you are using. Now go back to the customer class, this has changed since the first blog post, and the code is below.

using System;
using System.Configuration;
using System.Linq;
using Intuit.Ipp.Core;
using Intuit.Ipp.Data;
using Intuit.Ipp.DataService;
using Intuit.Ipp.QueryFilter;
using Intuit.Ipp.Security;
using QuickBooksIntergration.Models.CustomerInvoice;
using QuickBooksIntergration.Models.OAuth2ClientModel;

namespace QuickBooksIntergration.Models.CustomerModel
{
    public static class IntuitNewCustomer
    {
        public static string CreateNewCustomer(CustomerViewModel model)
        {
            try
            {
                bool doesFileExist = OAuthToken.DoesIntuitTokenFileExist();

                if (!doesFileExist) return null;

                var token = OAuthToken.RetrieveToken();

                string baseUrl = ConfigurationManager.AppSettings["baseUrl"];

                OAuth2RequestValidator oAuth2RequestValidator       = new OAuth2RequestValidator(token.AccessToken);
                ServiceContext serviceContext                       = new ServiceContext(realmId: token.RealmId, IntuitServicesType.QBO, oAuth2RequestValidator);
                serviceContext.IppConfiguration.MinorVersion.Qbo    = "62";
                serviceContext.IppConfiguration.BaseUrl.Qbo         = baseUrl;

                string displayName = $"{model.CompanyName}-{model.PostCode}";

                Customer customer = new Customer
                {
                    CompanyName         = model.CompanyName,
                    DisplayName         = displayName, //Must be unique
                    Title               = model.Title,
                    FamilyName          = model.FamilyName,
                    GivenName           = model.GivenName,
                    MiddleName          = model.MiddleName,
                    BillAddr = new PhysicalAddress
                    {
                        Line1                   = model.AddressLineOne,
                        City                    = model.City,
                        CountrySubDivisionCode  = model.County,
                        PostalCode              = model.PostCode,
                        Country                 = model.Country
                    },
                    ShipAddr = new PhysicalAddress
                    {
                        Line1                   = model.AddressLineOne,
                        City                    = model.City,
                        CountrySubDivisionCode  = model.County,
                        PostalCode              = model.PostCode,
                        Country                 = model.Country
                    },
                    PrimaryEmailAddr = new EmailAddress
                    {
                        Address = model.Email
                    },
                    PrimaryPhone = new TelephoneNumber
                    {
                        FreeFormNumber = model.PhoneNumber
                    }
                };

                QueryService customerQueryService = new QueryService(serviceContext);

                DataService dataService = new DataService(serviceContext);

                dataService.Add(customer);

                //Create our SQL select clause to get customer by DisplayName
                string whereClause = " WHERE DisplayName = '" + customer.DisplayName + "'";
                string selectQuery = "SELECT * FROM Customer" + whereClause;

                //Now get the customer as we will need it for the invoice.
                Customer customerDetails = customerQueryService.ExecuteIdsQuery(selectQuery).FirstOrDefault();
                //List customers = customerQueryService.ExecuteIdsQuery("SELECT * FROM Customer").ToList();

                var invoice             = CreateInvoice.GetInvoice(customerDetails);

                //Can also use AddAsync if required
                Invoice invoiceAdded    = dataService.Add(invoice);
                string invoiceNumber    = invoiceAdded.DocNumber;//Get the invoice number

                //Now send email, can also use SendEmailAsync if required
                dataService.SendEmail(invoiceAdded);

                return invoiceNumber;
            }
            catch (Exception e)
            {
                throw new ApplicationException(e.ToString());
            }
        }
    }
}

Next is the controller, again the code is below.

using System;
using System.Threading.Tasks;
using System.Web.Mvc;
using Intuit.Ipp.OAuth2PlatformClient;
using QuickBooksIntergration.Models;
using QuickBooksIntergration.Models.CustomerModel;
using QuickBooksIntergration.Models.OAuth2ClientModel;

namespace QuickBooksIntergration.Controllers
{
    public class CustomerController : Controller
    {
        [HttpGet]
        public ActionResult NewCustomer()
        {
            try
            {
                bool doesFileExist = OAuthToken.DoesIntuitTokenFileExist();

                if (!doesFileExist) return null;

                var token = OAuthToken.RetrieveToken();

                if (token.AccessTokenExpires < DateTime.Now)
                {
                    OAuth2Client client     = new OAuth2Client(clientID: ConfigurationTuples.ReturnIntuitAppSettings().clientId, clientSecret: ConfigurationTuples.ReturnIntuitAppSettings().clientSecret, redirectURI: ConfigurationTuples.ReturnIntuitAppSettings().redirectUrl, environment: ConfigurationTuples.ReturnIntuitAppSettings().appEnvironment);
                    var newToken            = Task.Run(() => client.RefreshTokenAsync(token.AccessRefreshToken)).Result;

                    SaveAccessTokenToDisk.SaveTokensToDisk(newToken.AccessToken, newToken.AccessTokenExpiresIn, newToken.RefreshToken, newToken.RefreshTokenExpiresIn, token.RealmId);
                }

                return View();
            }
            catch (Exception e)
            {
                throw new ApplicationException(e.ToString());
            }
        }

        [HttpPost]
        public ActionResult NewCustomer(CustomerViewModel model)
        {
            try
            {
                //You would do any validation and whatever else required here before submitting
                var invoiceNumber = IntuitNewCustomer.CreateNewCustomer(model);
                TempData["InvoiceNumber"] = $"Invoice created, the number is {invoiceNumber}";
                return View();
            }
            catch (Exception e)
            {
                throw new ApplicationException(e.ToString());
            }
        }
    }
}

And finally, we have our form which is below.

@model QuickBooksIntergration.Models.CustomerModel.CustomerViewModel
@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<div class="container">
    <div class="row">
        <div class="col-md-8 mt-5">
            <h4>List Of Customers</h4>
            @if (TempData["Status"] != null)
            {
                <p class="text-info p-3">@TempData["Status"]</p>
            }
            else
            {
                if (TempData["InvoiceNumber"] != null)
                {
                    <p class="text-success">@TempData["InvoiceNumber"]</p>
                }
                using (Html.BeginForm("NewCustomer", "Customer", FormMethod.Post, new { enctype = "multipart/form-data", id = "frmCustomer", name = "frmCustomer" }))
                {
                    @Html.LabelFor(x => x.CompanyName)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.CompanyName, new { Class = "form-control", Placeholder = "Company Name" })
                    </div>
                    @Html.LabelFor(x => x.Title)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.Title, new { Class = "form-control", Placeholder = "Title" })
                    </div>
                    @Html.LabelFor(x => x.GivenName)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.GivenName, new { Class = "form-control", Placeholder = "First name" })
                    </div>
                    @Html.LabelFor(x => x.MiddleName)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.MiddleName, new { Class = "form-control", Placeholder = "Middle name" })
                    </div>
                    @Html.LabelFor(x => x.FamilyName)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.FamilyName, new { Class = "form-control", Placeholder = "Family name" })
                    </div>
                    @Html.LabelFor(x => x.AddressLineOne)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.AddressLineOne, new { Class = "form-control", Placeholder = "Address" })
                    </div>
                    @Html.LabelFor(x => x.City)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.City, new { Class = "form-control", Placeholder = "City" })
                    </div>
                    @Html.LabelFor(x => x.County)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.County, new { Class = "form-control", Placeholder = "County/Region" })
                    </div>
                    @Html.LabelFor(x => x.PostCode)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.PostCode, new { Class = "form-control", Placeholder = "Post-Code/Zip" })
                    </div>
                    @Html.LabelFor(x => x.Country)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.Country, new { Class = "form-control", Placeholder = "Country" })
                    </div>
                    @Html.LabelFor(x => x.Email)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.Email, new { Class = "form-control", Placeholder = "Email" })
                    </div>
                    @Html.LabelFor(x => x.PhoneNumber)
                    <div class="input-group p-2">
                        @Html.TextBoxFor(x => x.PhoneNumber, new { Class = "form-control", Placeholder = "Phone number" })
                    </div>
                    <div class="input-group p-2">
                        <button type="submit" class="btn btn-success">Create Invoice</button>
                    </div>
                }
            }
        </div>
    </div>
</div>

To get QuickBooks to generate the invoice number, see the following link https://quickbooks.intuit.com/learn-support/en-uk/customise-forms/change-the-number-on-invoices-or-other-transactions/00/239181#

Basically, you need to turn 'Custom transaction numbers' off as the image below shows.

Turn Custom transaction numbers offOnce done, fill in the customer form and click 'Create Invoice', if all goes well, you should have something similar to the image below. QuickBooks API Create Invoice

Notice how it says under status, send, if you now check your email, you will see that you now have an email with the attachment

Invoice via emailAnd that's it for the series on creating customers and invoices using the QuickBook API, I hope you found it helpful, thanks for reading.