@happyvertical/accounting 0.99.0 → 0.100.0
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 +82 -0
- package/dist/chunks/{OAuthClient-DgRaQp_Y.js → OAuthClient-CF65pAW_.js} +2 -2
- package/dist/chunks/{OAuthClient-DgRaQp_Y.js.map → OAuthClient-CF65pAW_.js.map} +1 -1
- package/dist/chunks/{errors-Dvn2QzOB.js → errors-Dt7tUtsB.js} +24 -2
- package/dist/chunks/errors-Dt7tUtsB.js.map +1 -0
- package/dist/chunks/invoice-request-D6XcgNzI.js +51 -0
- package/dist/chunks/invoice-request-D6XcgNzI.js.map +1 -0
- package/dist/chunks/{quickbooks-DujZt_Gx.js → quickbooks-DLkypnT9.js} +55 -47
- package/dist/chunks/quickbooks-DLkypnT9.js.map +1 -0
- package/dist/chunks/{stripe-CZlx1zrs.js → stripe-Dpp7VB-7.js} +2 -2
- package/dist/chunks/{stripe-CZlx1zrs.js.map → stripe-Dpp7VB-7.js.map} +1 -1
- package/dist/errors.d.ts +21 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/providers/quickbooks/index.d.ts +2 -2
- package/dist/providers/quickbooks/index.d.ts.map +1 -1
- package/dist/providers/quickbooks/invoice-request.d.ts +29 -0
- package/dist/providers/quickbooks/invoice-request.d.ts.map +1 -0
- package/dist/types.d.ts +11 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/errors-Dvn2QzOB.js.map +0 -1
- package/dist/chunks/quickbooks-DujZt_Gx.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,6 +2,88 @@
|
|
|
2
2
|
|
|
3
3
|
Provider-neutral accounting synchronization with Stripe billing support.
|
|
4
4
|
|
|
5
|
+
## QuickBooks invoice creation and retries
|
|
6
|
+
|
|
7
|
+
Prepare a caller-owned request descriptor **once**, persist it with the approved
|
|
8
|
+
invoice in your durable outbox, then pass it on every create attempt:
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { prepareQuickBooksInvoiceRequest, QuickBooksWriteError } from '@happyvertical/accounting';
|
|
12
|
+
|
|
13
|
+
const quickbooksRequest = prepareQuickBooksInvoiceRequest(invoice, {
|
|
14
|
+
requestId: outbox.requestId, // e.g. a persisted UUID, never regenerated on retry
|
|
15
|
+
realmId: outbox.realmId,
|
|
16
|
+
environment: 'sandbox',
|
|
17
|
+
});
|
|
18
|
+
// Persist quickbooksRequest AND the invoice snapshot before invoking push.
|
|
19
|
+
try {
|
|
20
|
+
const result = await qbo.invoices.push({ ...invoice, quickbooksRequest });
|
|
21
|
+
// Persist result.externalId on the same outbox record.
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error instanceof QuickBooksWriteError && error.outcome === 'unknown') {
|
|
24
|
+
// Keep this record pending reconciliation; it may already exist remotely.
|
|
25
|
+
// Retry only the unchanged snapshot + descriptor, never with a new ID.
|
|
26
|
+
} else {
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The helper performs no HTTP. Its JSON-roundtrippable descriptor binds the exact
|
|
33
|
+
mapped QuickBooks payload (SHA-256) to the realm and sandbox/production environment.
|
|
34
|
+
`push()` and create-only `sync()` verify that binding before authentication or
|
|
35
|
+
HTTP, including on a new provider instance. Restore invoice date fields as `Date`
|
|
36
|
+
objects when loading an outbox. Mapping uses local calendar dates, so keep the
|
|
37
|
+
same timezone across workers; a changed mapped date fails closed. Changes to
|
|
38
|
+
mapped fields, realm, environment, or descriptor hash are rejected locally.
|
|
39
|
+
Request IDs accept this SDK's conservative subset: 1–50 ASCII letters, digits,
|
|
40
|
+
dots, underscores, and hyphens. The URL receives the caller's exact `requestid`.
|
|
41
|
+
|
|
42
|
+
The descriptor is a consistency check, **not an authorization token or durable
|
|
43
|
+
ID registry**. The caller must enforce uniqueness, tenant/realm ownership,
|
|
44
|
+
immutability, and concurrency in its outbox. Never prepare a new descriptor with
|
|
45
|
+
an old ID for different contents: a stateless SDK cannot detect that across
|
|
46
|
+
processes. Existing Stripe `idempotencyKey` is not a QuickBooks request ID.
|
|
47
|
+
Descriptors are create-only and are refused with `externalId`; update, send,
|
|
48
|
+
void, customer, vendor, and bill operations do not accept them.
|
|
49
|
+
|
|
50
|
+
QuickBooks reads retain automatic retry of transport failures, HTTP 429, and
|
|
51
|
+
5xx responses. Invoice creates with a descriptor retry these failures using
|
|
52
|
+
identical URL/body bytes; malformed successful invoice responses also remain
|
|
53
|
+
uncertain and may be retried under that identity. `maxRetries: 0` disables
|
|
54
|
+
retries; the default is three retries after the initial attempt. Timeout covers
|
|
55
|
+
reading the response as well as fetching it.
|
|
56
|
+
|
|
57
|
+
**All unkeyed QuickBooks writes now make one attempt**, including invoice
|
|
58
|
+
creates/updates/send/void and customer/vendor/bill creates and updates. This deliberately replaces the previous automatic write retry
|
|
59
|
+
behavior, which could duplicate a remotely accepted write. HTTP 429 is also
|
|
60
|
+
single-attempt for those operations. Stripe behavior is unchanged.
|
|
61
|
+
`QuickBooksWriteError` reports `outcome: 'rejected'` for an unkeyed HTTP client
|
|
62
|
+
rejection (including 429), or `outcome: 'unknown'` for transport failures,
|
|
63
|
+
server failures, or malformed success responses. **Every keyed failure is
|
|
64
|
+
conservatively `unknown`, including HTTP 4xx on the first locally observed
|
|
65
|
+
attempt.** A stateless SDK cannot prove that a persisted identity was never
|
|
66
|
+
sent by an earlier worker. This preserves uncertainty across process restarts
|
|
67
|
+
and later rejections without requiring mutable descriptor state. Client errors
|
|
68
|
+
still receive no automatic retry (except keyed 429 responses). Its realm, environment,
|
|
69
|
+
endpoint, optional request ID/payload hash, HTTP status, and cause support caller
|
|
70
|
+
reconciliation. A local validation or token acquisition error occurs before the
|
|
71
|
+
write and is not wrapped. Never treat an unknown outcome as a clean failure.
|
|
72
|
+
|
|
73
|
+
Intuit documents request-ID replay in its [API best practices](https://blogs.a.intuit.com/2018/09/10/quickbooks-online-api-best-practices/)
|
|
74
|
+
and [request ID field contract](https://developer.intuit.com/app/developer/qbo/docs/learn/learn-basic-field-definitions#request-id).
|
|
75
|
+
The [static documentation](https://static.developer.intuit.com/output_html/qbo/docs/learn/learn-basic-field-definitions.html)
|
|
76
|
+
confirms the 50-character limit and per-realm uniqueness requirement.
|
|
77
|
+
Our regression tests mock remote acceptance and response loss; they prove SDK
|
|
78
|
+
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,
|
|
81
|
+
repeat the identical request with the same ID, confirm the same Invoice.Id and
|
|
82
|
+
one invoice, and simulate a lost response before replaying it. Record realm,
|
|
83
|
+
environment, request ID, timestamps, and returned IDs without credentials.
|
|
84
|
+
No replay retention period or exactly-once guarantee is asserted here; reconcile
|
|
85
|
+
old or uncertain requests against QuickBooks before any new creation identity.
|
|
86
|
+
|
|
5
87
|
## Stripe invoices
|
|
6
88
|
|
|
7
89
|
Accounting amounts use currency major units: `12.34` means USD 12.34 and
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as __toCommonJS, i as __require, n as __esmMin, r as __exportAll, t as __commonJSMin } from "./quickbooks-
|
|
1
|
+
import { a as __toCommonJS, i as __require, n as __esmMin, r as __exportAll, t as __commonJSMin } from "./quickbooks-DLkypnT9.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-
|
|
18264
|
+
//# sourceMappingURL=OAuthClient-CF65pAW_.js.map
|