@happyvertical/accounting 0.100.3 → 0.101.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,8 +2,88 @@
2
2
 
3
3
  Provider-neutral accounting synchronization with Stripe billing support.
4
4
 
5
+ ## QuickBooks connection OAuth
6
+
7
+ Use the public connection helper to generate an accounting authorization URL,
8
+ exchange Intuit's callback, and revoke a refresh token:
9
+
10
+ ```ts
11
+ import { createQuickBooksOAuthClient } from '@happyvertical/accounting';
12
+
13
+ const oauth = await createQuickBooksOAuthClient({
14
+ clientId: process.env.QBO_CLIENT_ID!,
15
+ clientSecret: process.env.QBO_CLIENT_SECRET!,
16
+ environment: 'sandbox',
17
+ redirectUri: 'https://app.example.com/api/accounting/quickbooks/callback',
18
+ });
19
+
20
+ const url = oauth.authorizationUrl({ state: oneUseOpaqueState });
21
+ const connection = await oauth.exchangeCallback({
22
+ callbackUrl: request.url,
23
+ expectedState: oneUseOpaqueState,
24
+ });
25
+ await oauth.revoke({ refreshToken: connection.tokens.refreshToken });
26
+ ```
27
+
28
+ The helper requests only Intuit's QuickBooks accounting scope. Before the
29
+ official client receives a callback, it requires the configured origin and
30
+ path, exactly one nonempty state, code, and realm ID, and a constant-time state
31
+ match. Returned failures have stable `QuickBooksOAuthError.code` values and do
32
+ not retain provider errors that may contain callback URLs or credentials.
33
+
34
+ The application owns one-use state bound to its authenticated principal,
35
+ tenant, and environment; authorization to connect the returned realm;
36
+ encrypted token storage; and atomic connection persistence. The helper does
37
+ not make those application decisions. The redirect URI must also be registered
38
+ in Intuit's developer portal. See Intuit's [OAuth client authorization-code flow](https://github.com/intuit/oauth-jsclient#authorization-code-flow)
39
+ and [revocation helper](https://github.com/intuit/oauth-jsclient#revoke-access_token).
40
+
5
41
  ## QuickBooks invoice creation and retries
6
42
 
43
+ QuickBooks sales lines can carry explicit references to existing entities in the
44
+ target company:
45
+
46
+ ```ts
47
+ const invoice = {
48
+ // ...provider-neutral invoice fields...
49
+ currency: 'CAD',
50
+ subtotal: 100,
51
+ taxAmount: 5,
52
+ totalAmount: 105,
53
+ quickbooksMapping: { globalTaxCalculation: 'TaxExcluded' },
54
+ lineItems: [
55
+ {
56
+ description: 'Reviewed work',
57
+ quantity: 1,
58
+ unitPrice: 100,
59
+ quickbooksMapping: {
60
+ itemRef: '123', // Item.Id in this QuickBooks company
61
+ taxCodeRef: 'GST', // TaxCode.Id in this QuickBooks company
62
+ },
63
+ },
64
+ ],
65
+ };
66
+ ```
67
+
68
+ The QuickBooks adapter maps these values to `SalesItemLineDetail.ItemRef`,
69
+ `SalesItemLineDetail.TaxCodeRef`, `GlobalTaxCalculation`, and
70
+ `TxnTaxDetail.TotalTax`. It supports `TaxExcluded` and zero-tax
71
+ `NotApplicable`; tax-inclusive inputs are rejected because the provider-neutral
72
+ line model does not allocate included tax. Every mapped line must supply both
73
+ realm-specific references. The caller must validate that those IDs belong to
74
+ the configured company. See Intuit's [invoice API](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/invoice)
75
+ and [item API](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/item).
76
+
77
+ Legacy untaxed invoices without `quickbooksMapping` remain supported. The
78
+ adapter fails before authentication or HTTP when an input would otherwise be
79
+ silently discarded: nonzero line `discount`, nonzero numeric `taxRate`, generic
80
+ `taxCode`, `automaticTax`, inconsistent totals, partial mappings, or invalid
81
+ references. Explicit zero `discount` and `taxRate` are accepted. This mapping
82
+ API has no discount representation and does not silently net discounts into
83
+ prices. An explicit line `amount` must agree with `quantity × unitPrice`; the
84
+ adapter compares ordinary decimal calculations without assuming a fixed number
85
+ of decimal places for every currency.
86
+
7
87
  Prepare a caller-owned request descriptor **once**, persist it with the approved
8
88
  invoice in your durable outbox, then pass it on every create attempt:
9
89
 
@@ -76,8 +156,7 @@ The [static documentation](https://static.developer.intuit.com/output_html/qbo/d
76
156
  confirms the 50-character limit and per-realm uniqueness requirement.
77
157
  Our regression tests mock remote acceptance and response loss; they prove SDK
78
158
  identity/byte preservation and retry policy, **not live Intuit deduplication**.
79
- No sandbox credentials were available for this change. Before relying on remote
80
- idempotency, verify in an authorized sandbox: send a uniquely identified invoice,
159
+ Before relying on remote idempotency, verify in an authorized sandbox: send a uniquely identified invoice,
81
160
  repeat the identical request with the same ID, confirm the same Invoice.Id and
82
161
  one invoice, and simulate a lost response before replaying it. Record realm,
83
162
  environment, request ID, timestamps, and returned IDs without credentials.
@@ -1,4 +1,4 @@
1
- import { a as __toCommonJS, i as __require, n as __esmMin, r as __exportAll, t as __commonJSMin } from "./quickbooks-DLkypnT9.js";
1
+ import { a as __toCommonJS, i as __require, n as __esmMin, r as __exportAll, t as __commonJSMin } from "./rolldown-runtime-D1cXj70v.js";
2
2
  //#region ../../node_modules/.pnpm/atob@2.1.2/node_modules/atob/browser-atob.js
3
3
  var require_browser_atob = /* @__PURE__ */ __commonJSMin(((exports, module) => {
4
4
  (function(w) {
@@ -18261,4 +18261,4 @@ var require_OAuthClient = /* @__PURE__ */ __commonJSMin(((exports, module) => {
18261
18261
  //#endregion
18262
18262
  export default require_OAuthClient();
18263
18263
 
18264
- //# sourceMappingURL=OAuthClient-CF65pAW_.js.map
18264
+ //# sourceMappingURL=OAuthClient-x9rUYj0b.js.map