Skip to content
This repository has been archived by the owner on Aug 31, 2022. It is now read-only.
/ quickbooks-sdk Public archive

Quickbooks Node.js API SDK with modern Async API and TypeScript interfaces.

License

Notifications You must be signed in to change notification settings

MyUnisoft/quickbooks-sdk

Repository files navigation

Quickbooks Node.js SDK

An Intuit Quickbooks SDK for Node.js with modern `async/await` API πŸ’ƒ.

npm version license size Responsible Disclosure Policy

πŸ“’ About

Modern Intuit Quickbooks Node.js API SDK. Some API has been inspired by the node-quickbooks package.

⚠️ We have mainly implemented the features necessary for the use of MyUnisoft. Feel free to pull-request new or missing API.

πŸ”¬ Features.

  • Modern async/await API.
  • First class support of TypeScript.
  • Implement FEC API.
  • Use undici under the hood for http request.
  • Built-in Quickbooks Rate limitation.

🚧 Requirements

πŸš€ Getting Started

This package is available in the Node Package Repository and can be easily installed with npm or yarn.

$ npm i @myunisoft/quickbooks-node-sdk
# or
$ yarn add @myunisoft/quickbooks-node-sdk

πŸ“š Usage example

import Quickbooks from "@myunisoft/quickbooks-node-sdk";

// Retrieve the token with the `intuit-oauth` package (OAuth2).
const accessToken = "YourToken";

const Qb = new Quickbooks({
  accessToken,
  realmId: "0123456789",
  sandbox: false
});

const invoices = await Qb.Invoice.find();
console.log(invoices);

const account = await Qb.Account.findOne(42);
console.log(account);

const FECs = await Qb.Reports.FEC({
  start_date: "YYYY-MM-DD"
});
console.log(FECs);

The Quickbooks constructor options are described by the following TypeScript interface:

export interface QuickbooksOptions {
  realmId: string;
  accessToken: string;
  sandbox: boolean;
  /**
   * @default 63
   */
  minorVersion?: number;
}

You can use the .find(criteria?: SQLConditionalCriteria | SQLCriteria) method combined with criteria to dynamically build SQL:

const attachables = await Qb.Attachable.find({
  and: [
    { field: "AttachableRef.EntityRef.Type", value: "Invoice", operator: "=" },
    { field: "AttachableRef.EntityRef.value", value: 1, operator: "=" }
  ]
})
TypeScript definition
export type SQLOperator = "<" | ">" | "=" | "<=" | ">=" | "ILIKE" | "LIKE";

export interface SQLConditionalCriteria {
  or?: SQLCriteria[] | SQLConditionalCriteria[];
  and?: SQLCriteria[] | SQLConditionalCriteria[];
}

export interface SQLCriteria {
  field: string;
  value: string | number | boolean | null;
  operator: SQLOperator;
}

API

Basic API function

API Class

import * as QB from "../type";

abstract class API<T> {
  async find(criteria?: SQLConditionalCriteria | SQLCriteria): Promise<T[]>
  async findOne(id: number | QB.Reference): Promise<T>
  async query(sql: string): Promise<T[]>
  async create(entity: T): Promise<T | unknown>
}

Recurent Interface types

From type.ts

export interface Reference {
  value: string;
  name?: string;
}

export interface AbstractLine<T> {
  Id: string;
  DetailType: T;
  Amount: number;
  Description?: string;
  LineNum?: number;
}

export interface Addr {
  Id: number;
  Line1: string;
  Line2?: string;
  Line3?: string;
  Line4?: string;
  Line5?: string;
  City: string;
  Country: string;
  PostalCode: string;
  Lat: string;
  Long: string;
  CountrySubDivisionCode?: string;
}

export interface DateType {
  date?: string;
}

export interface TaxLine {
  Amount?: number;
  DetailType: "TaxLineDetail";
  TaxLineDetail: {
    TaxRateRef: Reference;
    NetAmountTaxable?: number;
    PercentBased?: boolean;
    TaxInclusiveAmount?: number;
    OverrideDeltaAmount?: number;
    TaxPercent?: number;
  };
}

export interface TxnTaxDetail {
  TxnTaxCodeRef?: Reference;
  TotalTax?: number;
  TaxLine?: TaxLine[];
}

export interface CustomField {
  DefinitionId?: string;
  StringValue?: string;
  Type?: "StringType";
  Name?: string;
}

export interface RootEntityProperties {
  Id?: string;
  domain: string;
  sparse: boolean;
  SyncToken?: string;
  MetaData: {
    CreateTime: string;
    LastUpdatedTime: string;
  };
  DocNumber?: string;
}

export interface MarkupInfo {
  PriceLevelRef?: Reference;
  Percent?: number;
  MarkUpIncomeAccountRef?: Reference;
}

export type BillableStatusEnum = "Billable" | "NotBillable" | "HadBeenBilled";
export type GlobalTaxCalculationEnum = "TaxExcluded" | "TaxInclusive" | "NotApplicable";

export interface LinkedTxn {
  TxnId: string;
  TxnType: string;
  TxnLineId?: string;
}

interface SalesItemLineDetail {
  TaxInclusiveAmt?: number;
  DiscountAmt?: number;
  ItemRef?: Reference;
  ClassRef?: Reference;
  TaxCodeRef?: Reference;
  MarkupInfo?: MarkupInfo;
  ItemAccountRef: Reference;
  ServiceDate: DateType;
  DiscountRate: number;
  Qty?: number;
  UnitPrice?: number;
  TaxClassificaitionRef: Reference;
}
type SalesItemLine = AbstractLine<"SalesItemLineDetail"> & {SalesItemLineDetail: SalesItemLineDetail}

interface GroupLineDetail {
  Quantity?: number;
  Line: SalesItemLineDetail[];
  GroupItemRef: Reference;
}
type GroupLine = Omit<AbstractLine<"GroupLineDetail">, "Amount"> & {GroupLineDetail: GroupLineDetail}


interface DescriptionOnlyLineDetail {
  TaxCodeRef?: Reference;
  Date?: DateType
}
type DescriptionOnlyLine = AbstractLine<"DescriptionOnlyLineDetail"> & {DescriptionOnlyLineDetail: DescriptionOnlyLineDetail}


interface DiscountLineDetail {
  ClassRef?: Reference;
  TaxCodeRef?: Reference;
  DiscountAccountRef?: Reference;
  PercentBased?: boolean;
  DismountPercent?: number;
}
type DiscountLine = AbstractLine<"DiscountLineDetail"> & {DiscountLineDetail: DiscountLineDetail}

interface SubTotalLineDetail {
  ItemRef: Reference;
}
type SubTotalLine = AbstractLine<"SubTotalLineDetail"> & {SubTotalLineDetail: SubTotalLineDetail}


export type InvoiceLine = SalesItemLine | GroupLine |
DescriptionOnlyLine | DiscountLine | SubTotalLine

FEC

FEC Options
export interface FECReportOptions {
  attachment?: "TEMPORARY" | "NONE";
  withQboIdentifier?: boolean;
  start_date: string;
  end_date?: string;
  add_due_date?: boolean;
}
FEC Interface
export interface FECRowColData {
  id?: string;
  value: string;
  href?: string;
}

export interface FECRowColumn {
  ColType: "Account" | "Money";
  ColTitle?: string;
  MetaData?: {
    Name?: string;
    Value: string;
  }
}

export interface FECRow {
  type: "Data" | "Section";
  ColData: FECRowColData[];
  Summary?: any;
  Rows?: any;
  Header?: any;
}

export interface FEC {
  Header: {
    Customer?: string;
    ReportName?: string;
    Vendor?: string;
    Options?: {
      Name?: string;
      Value?: string;
    }
    Item?: string;
    Employee?: string;
    ReportBasis?: "Cash" | "Accrual";
    StartPeriod?: string;
    Class?: string;
    Currency?: string;
    EndPeriod?: string;
    Time?: string;
    Department?: string;
    SummarizeColumnsBy?: string;
  },
  Rows: {
    Row: FECRow;
  },
  Columns: {
    Column: FECRowColumn[];
  }
}

Account

IAccount Interface

From API/account.ts

import * as QB from "../type";

interface IAccount extends QB.RootEntityProperties {
  Name: string;
  AcctNum?: string;
  CurrencyRef: QB.Reference;
  ParentRef: QB.Reference;
  Description?: string;
  Active?: boolean;
  SubAccount?: boolean;
  Classification?: string;
  FullyQualifiedName?: string;
  TxnLocationType?: "WithinFrance" | "FranceOverseas" | "OutsideFranceWithEU" | "OutsideEU";
  AccountType: string;
  CurrentBalanceWithSubAccounts?: number;
  AccountAlias: string;
  TaxCodeRef?: QB.Reference;
  AccountSubType: string;
  CurrentBalance: number;
}

Attachable

IAttachable Interface

From API/attachable.ts

import Quickbooks from "../quickbooks";

interface AttachableRef {
  IncludeOnSend?: boolean;
  LineInfo?: string;
  NoRefOnly?: boolean;
  CustomField?: QB.CustomField[];
  Inactive?: boolean;
  EntityRef?: {
    value: string;
    type?: "Invoice";
  };
}

interface IAttachable extends QB.RootEntityProperties {
  FileName: string;
  Note?: string;
  Category?: "Contact Photo" | "Document" | "Image" | "Receipt" | "Signature" | "Sound" | "Other";
  ContentType?: string;
  PlaceName?: string;
  AttachableRef: AttachableRef[];
  Long?: string;
  Tag?: string;
  Lat?: string;
  FileAccessUri?: string;
  Size?: number;
  ThumbnailFileAccessUri?: string;
  TempDownloadUri?: string;
  ThumbnailTempDownloadUri?: string;
}

CreditMemo

ICreditMemo Interface

From API/creditMemo.ts

import Quickbooks from "../quickbooks";

interface ICreditMemo extends QB.RootEntityProperties {
  Line: QB.InvoiceLine[];
  CustomerRef: QB.Reference;
  CurrencyRef?: QB.Reference;
  BillEmail?: {
    Address?: string;
  };
  TxnDate?: string;
  CustomField?: QB.CustomField[];
  ClassRef?: QB.Reference;
  PrintStatus?: string;
  SalesTermRef?: QB.Reference;

  GlobalTaxCalculation?: QB.GlobalTaxCalculationEnum;
  TotalAmt?: string;
  InvoiceRef?: QB.Reference;
  TransactionLocationType?: "WithinFrance" | "FranceOverseas" | "OutsideFranceWithEU" | "OutsideEU";
  ApplyTaxAfterDiscount?: boolean;
  DocNumber?: string;
  PrivateNote?: string;
  CustomerMemo?: string;
  TxnTaxDetail?: QB.TxnTaxDetail;
  PaymentMethodRef?: QB.Reference;
  ExchangeRate?: number;
  ShipAddr?: QB.Addr;
  DepartmentRef?: QB.Reference;
  EmailStatus?: string;
  BillAddr?: QB.Addr;
  HomeBalance?: number;
  RemainingCredit?: number;
  RecurDataRef?: QB.Reference;
  TaxExemptionRef?: QB.Reference;
  Balance?: number;
  HomeTotalAmt?: number;
}

Customer

ICustomer Interface

From API/customer.ts

import Quickbooks from "../quickbooks";

interface ICustomer extends QB.RootEntityProperties {
  DisplayName?: string;
  Title?: string;
  GivenName?: string;
  MiddleName?: string;
  Suffix?: string;
  FamilyName?: string;
  PrimaryEmailAddr?: {
    Address?: string;
  };
  ResaleNum?: string;
  SecondaryTaxIdentifier?: string;
  ARAccountRef?: QB.Reference
  DefaultTaxCodeRef: QB.Reference;
  PreferredDeliveryMethod?: string;
  GSTIN?: string;
  SalesTermRef?: QB.Reference;
  CustomerTypeRef?: QB.Reference;
  Fax?: {
    FreeFormNumber?: string;
  }
  BusinessNumber?: string;
  BillWithParent?: boolean;
  CurrencyRef?: QB.Reference;
  Mobile?: {
    FreeFormNumber?: string;
  }
  Job?: boolean;
  BalanceWithJobs?: number;
  PrimaryPhone?: {
    FreeFormNumber: string;
  };
  OpenBalanceDate?: QB.DateType;
  Taxable?: boolean;
  AlternatePhone?: {
    FreeFormNumber?: string;
  }
  ParentRef: QB.Reference;
  Notes?: string;
  WebAddr?: {
    URI?: string;
  }
  Active?: boolean;
  CompanyName?: string;
  Balance?: number;
  ShipAddr?: QB.Addr;
  PaymentMethodRef?: QB.Reference;
  IsProject?: boolean;
  Source?: string;
  PrimaryTaxIdentifier?: string;
  GSTRegistrationType?: "GST_REG_REG" | "GST_REG_COMP" | "GST_UNREG" | "CONSUMER" | "OVERSEAS" | "SEZ";
  PrintOnCheckName?: string;
  BillAddr?: QB.Addr;
  FullyQualifiedName?: string;
  Level?: number;
  TaxExemptionReasonId?: number;
}

Invoice

IInvoice Interface

From API/invoice.ts

import * as QB from "../type";

interface InvoiceLinkedTxn {
  TxnId: string;
  TxnLineId?: string;
  TxnType: "Estimate" | "TimeActivity" | "PurchaseOrder" | "BillPaymentCheck";
}

interface IInvoice extends QB.RootEntityProperties {
  Line: QB.InvoiceLine[];
  CustomerRef: QB.Reference;
  CurrencyRef?: QB.Reference;
  DocNumber?: string;
  BillEmail?: {
    Address?: string;
  };
  TxnDate: string;
  ShipFromAddr?: QB.Addr;
  ShipDate?: string;
  TrackingNum?: number;
  ClassRef?: QB.Reference;
  PrintStatus?: string;
  SalesTermRef?: QB.Reference;
  TxnSource?: string;
  LinkedTxn?: InvoiceLinkedTxn[];
  DepositeToAccountRef?: QB.Reference;
  GlobalTaxCalculation?: QB.GlobalTaxCalculationEnum;
  AllowOnlineACHPayment?: boolean;
  TransactionLocationType?: string;
  DueDate?: QB.DateType;
  PrivateNote?: string;
  BillEmailCc?: {
    Address?: string;
  }
  CustomerMemo?: QB.Reference;
  EmailStatus?: string;
  ExchangeRate?: number;
  Deposit?: number;
  TxnTaxDetail?: QB.TxnTaxDetail;
  AllowOnlineCreditCardPayment?: boolean;
  CustomField?: QB.CustomField[];
  ShipAddr?: QB.Addr;
  DepartmentRef?: QB.Reference;
  BillEmailBcc?: {
    Address?: string;
  }
  ShipMethodRef?: QB.Reference;
  BillAddr?: QB.Addr;
  ApplyTaxAfterDiscount?: boolean;
  HomeBalance?: number;
  DeliveryInfo?: {
    DeliveryType?: "Email" | "Tradeshift";
    DeliveryTime?: {
      dateTime?: string;
    }
  }
  TotalAmt?: string;
  InvoiceLink?: string;
  RecurDataRef: QB.Reference;
  TaxExemptionRef?: QB.Reference;
  Balance?: number;
  HomeTotalAmt?: number;
  FreeFormAddress?: boolean;
  AllowOnlinePayment?: boolean;
  AllowIPNPayment?: boolean;
}

Item

IItem Interface

From API/item.ts

import Quickbooks from "../quickbooks";

interface IItem extends QB.RootEntityProperties {
  ItemCategoryType: "Service" | "Service";
  Name: string;
  InvStartDate?: QB.DateType;
  Type: "Service" | "Inventory" | "NonInventory";
  QtyOnHand?: number;
  AssetAccountRef?: QB.Reference;
  Sku?: string;
  SalesTaxIncluded?: boolean;
  TrackQtyOnHand?: boolean;
  SalesTaxCodeRef?: QB.Reference;
  ClassRef?: QB.Reference;
  Source?: string;
  PurchaseTaxIncluded?: boolean;
  Description?: string;
  AbatementRate?: number;
  SubItem?: boolean;
  Taxable?: boolean;
  UQCDisplayText?: string;
  ReorderPoint?: number;
  PurchaseDesc?: string;
  PrefVendorRef?: QB.Reference;
  Active?: boolean;
  UQCId?: string;
  ReverseChargeRate?: number;
  PurchaseTaxCodeRef?: QB.Reference;
  ServiceType?: string;
  PurchaseCost?: number;
  ParentRef: QB.Reference;
  UnitPrice?: number;
  FullyQualifiedName?: string;
  ExpenseAccountRef?: QB.Reference;
  Level?: number;
  IncomeAccountRef?: QB.Reference;
  TaxClassificationRef?: QB.Reference;
}

Purchase

IPurchase Interface

From API/purchase.ts

import Quickbooks from "../quickbooks";

interface ItemBasedExpenseLineDetail {
  TaxInclusiveAmt?: number;
  ItemRef?: QB.Reference;
  CustomerRef?: QB.Reference;
  PriceLevelRef?: QB.Reference;
  ClassRef?: QB.Reference;
  TaxCodeRef?: QB.Reference;
  MarkupInfo?: QB.MarkupInfo;
  BillableStatus?: QB.BillableStatusEnum;
  Qty?: number;
  UnitPrice?: number;
}

interface AccountBasedExpenseLineDetail {
  AccountRef: QB.Reference;
  TaxAmount?: number;
  TaxInclusiveAmt?: number;
  ClassRef?: QB.Reference;
  TaxCodeRef?: QB.Reference;
  MarkupInfo?: QB.MarkupInfo;
  BillableStatus?: QB.BillableStatusEnum;
  CustomerRef?: QB.Reference;
}

type AccountBasedExpenseLine = QB.AbstractLine<"AccountBasedExpenseLineDetail">
  & { AccountBasedExpenseLineDetail: AccountBasedExpenseLineDetail; };
type ItemBasedExpenseLine = QB.AbstractLine<"ItemBasedExpenseLineDetail">
  & {
    ItemBasedExpenseLineDetail: ItemBasedExpenseLineDetail;
    LinkedTxn?: QB.LinkedTxn[];
  };

type PurchaseLine = AccountBasedExpenseLine | ItemBasedExpenseLine;

interface IPurchase extends QB.RootEntityProperties {
  Line: PurchaseLine[];
  PaymentType: "Cash" | "Check" | "CreditCard";
  AccountRef: QB.Reference;
  CurrencyRef?: QB.Reference;
  TxnDate?: string;
  PrintStatus: string;
  RemitToAddr?: QB.Addr;
  TxnSource?: string;
  LinkedTxn?: QB.LinkedTxn[];
  GlobalTaxCalculation?: QB.GlobalTaxCalculationEnum;
  TransactionLocationType?: "WithinFrance" | "FranceOverseas" | "OutsideFranceWithEU" | "OutsideEU";
  DocNumber?: string;
  PrivateNote?: string;
  Credit?: boolean;
  TxnTaxDetail?: QB.TxnTaxDetail;
  PaymentMethodRef?: QB.Reference;
  PurchaseEx: Record<string, unknown>
  EchangeRate?: number;
  DepartmentRef?: QB.Reference;
  EntityRef?: QB.Reference;
  IncludeInAnnualTPAR?: boolean;
  TotalAmt?: string;
  CustomField?: any[];
}

TaxRate

ITaxRate Interface

From API/taxRate.ts

import Quickbooks from "../quickbooks";

interface EffectiveTaxRate {
  RateValue: number;
  EffectiveDate: string;
}

interface ITaxRate extends QB.RootEntityProperties {
  RateValue?: string;
  Name?: string;
  AgencyRef?: QB.Reference;
  SpecialTaxType?: string;
  EffectiveTaxRate?: EffectiveTaxRate[];
  DisplayType?: string;
  TaxReturnLineRef: QB.Reference;
  Active: boolean;
  OriginalTaxRate?: string;
  Description: string;
}

Vendor

IVendor Interface

From API/vendor.ts

import Quickbooks from "../quickbooks";

interface IVendor extends QB.RootEntityProperties {
  Title?: string;
  GivenName?: string;
  MiddleName?: string;
  Suffix?: string;
  FamilyName?: string;
  PrimaryEmailAddr?: {
    Address?: string;
  }
  DisplayName?: string;
  OtherContactInfo?: {
    Type?: string;
    Telephone?: string;
  }
  APAccountRef?: QB.Reference;
  TermeRef?: QB.Reference;
  Source?: string;
  GSTIN?: string;
  T4AEligible?: boolean;
  Fax?: {
    FreeFormNumber?: string
  }
  BusinessNumber?: string;
  CurrencyRef?: QB.Reference;
  HasTPAR?: boolean;
  TaxReportingBasis?: string;
  Mobile?: {
    FreeFormNumber?: string;
  }
  PrimaryPhone?: {
    FreeFormNumber?: string;
  }
  Active?: boolean;
  AlternatePhone?: {
    FreeFormNumber?: string;
  }
  Vendor1099?: boolean;
  CostRate?: string;
  BillRate?: number;
  WebAddr?: {
    URI?: string;
  }
  T5018Eligible?: boolean;
  CompanyName?: string
  VendorPaymentBankDetail?: {
    BankAccountName?: string;
    BankBranchIdentifier: string;
    BankAccountNumber: string;
    StatementText: string;
  }
  TaxIdentifier?: string;
  AcctNum?: string;
  GSTRegistrationType?: "GST_REG_REG" | "GST_REG_COMP" | "GST_UNREG" | "CONSUMER" | "OVERSEAS" | "SEZ" | "DEEMED";
  PrintOnCheckName?: string;
  BillAddr?: QB.Addr;
  Balance: number;
}

Contributors ✨

All Contributors

Thanks goes to these wonderful people (emoji key):


Gentilhomme

πŸ’» πŸ“– πŸ‘€ πŸ›

Alexandre Malaj

πŸ’» πŸ“– πŸ‘€ πŸ›

License

MIT

About

Quickbooks Node.js API SDK with modern Async API and TypeScript interfaces.

Resources

License

Security policy

Stars

Watchers

Forks