@peable.to/contracts 6.1.0 → 6.2.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/dist/cjs/resources/billingEngine/index.js +4 -1
- package/dist/cjs/resources/billingEngine/quotes.js +342 -0
- package/dist/cjs/resources/events/events.js +4 -0
- package/dist/cjs/vocabulary/errors.js +3 -0
- package/dist/cjs/vocabulary/events.js +4 -0
- package/dist/cjs/vocabulary/index.js +1 -0
- package/dist/cjs/vocabulary/invoices.js +3 -0
- package/dist/cjs/vocabulary/quotes.js +31 -0
- package/dist/esm/resources/billingEngine/index.js +4 -1
- package/dist/esm/resources/billingEngine/quotes.js +339 -0
- package/dist/esm/resources/events/events.js +4 -0
- package/dist/esm/vocabulary/errors.js +3 -0
- package/dist/esm/vocabulary/events.js +4 -0
- package/dist/esm/vocabulary/index.js +1 -0
- package/dist/esm/vocabulary/invoices.js +3 -0
- package/dist/esm/vocabulary/quotes.js +28 -0
- package/dist/types/resources/billingEngine/index.d.ts +839 -1
- package/dist/types/resources/billingEngine/invoices.d.ts +12 -0
- package/dist/types/resources/billingEngine/quotes.d.ts +1032 -0
- package/dist/types/resources/events/events.d.ts +16 -0
- package/dist/types/resources/events/index.d.ts +54 -2
- package/dist/types/resources/events/webhookDeliveries.d.ts +12 -0
- package/dist/types/resources/events/webhookEndpoints.d.ts +52 -4
- package/dist/types/resources/payments/disputes.d.ts +10 -10
- package/dist/types/resources/payments/index.d.ts +6 -6
- package/dist/types/vocabulary/errors.d.ts +3 -0
- package/dist/types/vocabulary/events.d.ts +4 -0
- package/dist/types/vocabulary/index.d.ts +1 -0
- package/dist/types/vocabulary/invoices.d.ts +1 -1
- package/dist/types/vocabulary/quotes.d.ts +27 -0
- package/package.json +1 -1
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { listOf } from '../../common/envelopes.js';
|
|
3
|
+
import { defineObject, expandable } from '../../common/objects.js';
|
|
4
|
+
import { expandOnlyQuery, expandParam, idParam, listQuery, metadataCreateParam, metadataUpdateParam, unixSecondsParam, } from '../../common/params.js';
|
|
5
|
+
import { amount, currency, livemode, metadata, unixSeconds } from '../../common/primitives.js';
|
|
6
|
+
import { defineRoute } from '../../route.js';
|
|
7
|
+
import { AUTOMATIC_TAX_STATUSES } from '../../vocabulary/invoices.js';
|
|
8
|
+
import { QUOTE_LIMITS, QUOTE_STATUSES } from '../../vocabulary/quotes.js';
|
|
9
|
+
import { COLLECTION_METHODS } from '../../vocabulary/subscriptions.js';
|
|
10
|
+
import { checkoutLineItemSchema } from '../checkout/shared.js';
|
|
11
|
+
import { automaticTaxParam, daysUntilDueParam, discountsParam, shortText } from './params.js';
|
|
12
|
+
import { discountSchema } from './subscriptions.js';
|
|
13
|
+
/**
|
|
14
|
+
* Quotes (`qt_…`) — Stripe's Quotes on Orbit's native billing engine (ADR 0018
|
|
15
|
+
* §5). A quote prices catalog Prices for one customer: a `draft` is edited,
|
|
16
|
+
* `finalize` numbers it and fixes its discount and Peable Tax (failing closed,
|
|
17
|
+
* never zero), and `accept` turns it into native billing objects — an invoice
|
|
18
|
+
* for one-time lines, a subscription with its first invoice for recurring ones
|
|
19
|
+
* (one-time lines then ride on that first invoice). Its lines are Stripe's
|
|
20
|
+
* `item`, the same object a Checkout Session's lines are.
|
|
21
|
+
*/
|
|
22
|
+
const totalDetailsSchema = z
|
|
23
|
+
.object({
|
|
24
|
+
amount_discount: amount,
|
|
25
|
+
amount_shipping: amount.describe('Always `0`: a quote ships nothing.'),
|
|
26
|
+
amount_tax: amount
|
|
27
|
+
.nullable()
|
|
28
|
+
.describe('Every tax, inclusive and exclusive; `null` on a draft whose tax is not known yet.'),
|
|
29
|
+
})
|
|
30
|
+
.strict();
|
|
31
|
+
export const quoteSchema = defineObject('quote', 'Quote', z
|
|
32
|
+
.object({
|
|
33
|
+
id: z.string(),
|
|
34
|
+
object: z.literal('quote'),
|
|
35
|
+
livemode,
|
|
36
|
+
number: z
|
|
37
|
+
.string()
|
|
38
|
+
.nullable()
|
|
39
|
+
.describe('`null` while a draft; `QT-PREFIX-0001` once finalized — per merchant.'),
|
|
40
|
+
status: z.enum(QUOTE_STATUSES),
|
|
41
|
+
customer: expandable('customer', '`cus_…`, or the Customer with `expand[]=customer`.'),
|
|
42
|
+
currency,
|
|
43
|
+
collection_method: z.enum(COLLECTION_METHODS),
|
|
44
|
+
invoice_settings: z
|
|
45
|
+
.object({
|
|
46
|
+
days_until_due: z
|
|
47
|
+
.number()
|
|
48
|
+
.int()
|
|
49
|
+
.nullable()
|
|
50
|
+
.describe("`send_invoice` only; the billing settings' default when `null`."),
|
|
51
|
+
})
|
|
52
|
+
.strict(),
|
|
53
|
+
subscription_data: z
|
|
54
|
+
.object({
|
|
55
|
+
description: z.string().nullable(),
|
|
56
|
+
trial_period_days: z.number().int().nullable(),
|
|
57
|
+
metadata,
|
|
58
|
+
})
|
|
59
|
+
.strict()
|
|
60
|
+
.describe('What the subscription an accepted quote with recurring lines starts with.'),
|
|
61
|
+
discount: discountSchema.nullable(),
|
|
62
|
+
automatic_tax: z
|
|
63
|
+
.object({
|
|
64
|
+
enabled: z.boolean(),
|
|
65
|
+
status: z.enum(AUTOMATIC_TAX_STATUSES).nullable(),
|
|
66
|
+
tax_calculation: z
|
|
67
|
+
.string()
|
|
68
|
+
.nullable()
|
|
69
|
+
.describe('The Peable Tax calculation (`taxcalc_…`) the quote finalized with.'),
|
|
70
|
+
})
|
|
71
|
+
.strict(),
|
|
72
|
+
amount_subtotal: amount.describe('Every line before discount and tax (one period of a recurring line).'),
|
|
73
|
+
amount_total: amount.describe('`amount_subtotal - amount_discount + exclusive tax`.'),
|
|
74
|
+
total_details: totalDetailsSchema,
|
|
75
|
+
expires_at: unixSeconds.describe('An open quote is cancelled at this instant.'),
|
|
76
|
+
header: z.string().nullable(),
|
|
77
|
+
description: z.string().nullable(),
|
|
78
|
+
footer: z.string().nullable(),
|
|
79
|
+
invoice: expandable('invoice', "The invoice accepting made (`in_…`, expandable): the one-time invoice, or the subscription's first.").nullable(),
|
|
80
|
+
subscription: expandable('subscription', 'The subscription accepting made (`sub_…`, expandable); `null` without recurring lines.').nullable(),
|
|
81
|
+
status_transitions: z
|
|
82
|
+
.object({
|
|
83
|
+
finalized_at: unixSeconds.nullable(),
|
|
84
|
+
accepted_at: unixSeconds.nullable(),
|
|
85
|
+
canceled_at: unixSeconds.nullable(),
|
|
86
|
+
})
|
|
87
|
+
.strict(),
|
|
88
|
+
test_clock: z.string().nullable(),
|
|
89
|
+
metadata,
|
|
90
|
+
created: unixSeconds,
|
|
91
|
+
})
|
|
92
|
+
.strict(), {
|
|
93
|
+
examples: [
|
|
94
|
+
{
|
|
95
|
+
id: 'qt_0193b8f2c1a87d3e9f4a',
|
|
96
|
+
object: 'quote',
|
|
97
|
+
livemode: false,
|
|
98
|
+
number: 'QT-ACME-0001',
|
|
99
|
+
status: 'open',
|
|
100
|
+
customer: 'cus_0193b8f2c1a87d3e9f4a',
|
|
101
|
+
currency: 'EUR',
|
|
102
|
+
collection_method: 'send_invoice',
|
|
103
|
+
invoice_settings: { days_until_due: 30 },
|
|
104
|
+
subscription_data: { description: null, trial_period_days: null, metadata: {} },
|
|
105
|
+
discount: null,
|
|
106
|
+
automatic_tax: { enabled: false, status: null, tax_calculation: null },
|
|
107
|
+
amount_subtotal: '120000',
|
|
108
|
+
amount_total: '120000',
|
|
109
|
+
total_details: { amount_discount: '0', amount_shipping: '0', amount_tax: '0' },
|
|
110
|
+
expires_at: 1796342400,
|
|
111
|
+
header: 'Annual support',
|
|
112
|
+
description: null,
|
|
113
|
+
footer: null,
|
|
114
|
+
invoice: null,
|
|
115
|
+
subscription: null,
|
|
116
|
+
status_transitions: { finalized_at: 1793750400, accepted_at: null, canceled_at: null },
|
|
117
|
+
test_clock: null,
|
|
118
|
+
metadata: {},
|
|
119
|
+
created: 1793750400,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
});
|
|
123
|
+
// ---- Requests ------------------------------------------------------------------------
|
|
124
|
+
const quoteLineItemParams = z
|
|
125
|
+
.object({
|
|
126
|
+
price: idParam.describe('An active, licensed catalog Price (`price_…`), one-time or recurring.'),
|
|
127
|
+
quantity: z
|
|
128
|
+
.number()
|
|
129
|
+
.int()
|
|
130
|
+
.min(1)
|
|
131
|
+
.max(QUOTE_LIMITS.quantityMax)
|
|
132
|
+
.optional()
|
|
133
|
+
.describe('Default 1.'),
|
|
134
|
+
})
|
|
135
|
+
.strict();
|
|
136
|
+
const lineItemsParam = z
|
|
137
|
+
.array(quoteLineItemParams)
|
|
138
|
+
.min(1)
|
|
139
|
+
.max(QUOTE_LIMITS.lineItemsMax)
|
|
140
|
+
.describe('Each price once, in one currency; every recurring price on one interval. Replaces every line on an update.');
|
|
141
|
+
const invoiceSettingsParam = z.object({ days_until_due: daysUntilDueParam.optional() }).strict();
|
|
142
|
+
const subscriptionDataParam = z
|
|
143
|
+
.object({
|
|
144
|
+
description: shortText(500).optional(),
|
|
145
|
+
trial_period_days: z.number().int().min(1).max(QUOTE_LIMITS.trialPeriodDaysMax).optional(),
|
|
146
|
+
metadata: metadataCreateParam.optional(),
|
|
147
|
+
})
|
|
148
|
+
.strict();
|
|
149
|
+
export const createQuoteParams = z
|
|
150
|
+
.object({
|
|
151
|
+
customer: idParam,
|
|
152
|
+
line_items: lineItemsParam,
|
|
153
|
+
collection_method: z
|
|
154
|
+
.enum(COLLECTION_METHODS)
|
|
155
|
+
.optional()
|
|
156
|
+
.describe('Default `charge_automatically`; a FairCoin (`FAIR`) quote is always `send_invoice`.'),
|
|
157
|
+
invoice_settings: invoiceSettingsParam.optional(),
|
|
158
|
+
subscription_data: subscriptionDataParam.optional(),
|
|
159
|
+
discounts: discountsParam.optional().describe('At most one: a coupon or a promotion code.'),
|
|
160
|
+
automatic_tax: automaticTaxParam.optional(),
|
|
161
|
+
expires_at: unixSecondsParam
|
|
162
|
+
.optional()
|
|
163
|
+
.describe("Default: 30 days from now (the customer's test clock time when it has one)."),
|
|
164
|
+
header: shortText(QUOTE_LIMITS.headerMax).optional(),
|
|
165
|
+
description: shortText(QUOTE_LIMITS.descriptionMax).optional(),
|
|
166
|
+
footer: shortText(QUOTE_LIMITS.footerMax).optional(),
|
|
167
|
+
metadata: metadataCreateParam.optional(),
|
|
168
|
+
expand: expandParam.optional(),
|
|
169
|
+
})
|
|
170
|
+
.strict();
|
|
171
|
+
/** Drafts only, except `metadata`. A field sent as `""` is cleared. */
|
|
172
|
+
export const updateQuoteParams = z
|
|
173
|
+
.object({
|
|
174
|
+
line_items: lineItemsParam.optional(),
|
|
175
|
+
collection_method: z.enum(COLLECTION_METHODS).optional(),
|
|
176
|
+
invoice_settings: invoiceSettingsParam.optional(),
|
|
177
|
+
subscription_data: subscriptionDataParam.optional(),
|
|
178
|
+
discounts: z.union([discountsParam, z.literal('')]).optional(),
|
|
179
|
+
automatic_tax: automaticTaxParam.optional(),
|
|
180
|
+
expires_at: unixSecondsParam.optional(),
|
|
181
|
+
header: z.union([shortText(QUOTE_LIMITS.headerMax), z.literal('')]).optional(),
|
|
182
|
+
description: z.union([shortText(QUOTE_LIMITS.descriptionMax), z.literal('')]).optional(),
|
|
183
|
+
footer: z.union([shortText(QUOTE_LIMITS.footerMax), z.literal('')]).optional(),
|
|
184
|
+
metadata: metadataUpdateParam.optional(),
|
|
185
|
+
expand: expandParam.optional(),
|
|
186
|
+
})
|
|
187
|
+
.strict();
|
|
188
|
+
export const finalizeQuoteParams = z
|
|
189
|
+
.object({
|
|
190
|
+
expires_at: unixSecondsParam.optional().describe('A new expiry, set as it finalizes.'),
|
|
191
|
+
expand: expandParam.optional(),
|
|
192
|
+
})
|
|
193
|
+
.strict();
|
|
194
|
+
/** The body of `accept` and `cancel`: nothing but `expand[]`. */
|
|
195
|
+
export const quoteActionParams = z.object({ expand: expandParam.optional() }).strict();
|
|
196
|
+
export const listQuotesQuery = listQuery({
|
|
197
|
+
customer: idParam.optional(),
|
|
198
|
+
status: z.enum(QUOTE_STATUSES).optional(),
|
|
199
|
+
});
|
|
200
|
+
/** A quote's lines, in their order; `created` does not apply to them. */
|
|
201
|
+
export const listQuoteLineItemsQuery = listQuery({});
|
|
202
|
+
// ---- Routes --------------------------------------------------------------------------
|
|
203
|
+
const quoteId = { id: 'The quote (`qt_…`).' };
|
|
204
|
+
export const quoteRoutes = [
|
|
205
|
+
defineRoute({
|
|
206
|
+
operationId: 'createQuote',
|
|
207
|
+
method: 'post',
|
|
208
|
+
path: '/v1/quotes',
|
|
209
|
+
tag: 'Quotes',
|
|
210
|
+
summary: 'Create a quote',
|
|
211
|
+
description: "A draft for one customer, priced from catalog Prices with the catalog's own pricing. Its tax is computed when it finalizes.",
|
|
212
|
+
auth: 'service',
|
|
213
|
+
scope: 'payments:write',
|
|
214
|
+
idempotent: true,
|
|
215
|
+
body: createQuoteParams,
|
|
216
|
+
response: quoteSchema,
|
|
217
|
+
sdk: 'quotes.create',
|
|
218
|
+
expandable: 'quote',
|
|
219
|
+
}),
|
|
220
|
+
defineRoute({
|
|
221
|
+
operationId: 'listQuotes',
|
|
222
|
+
method: 'get',
|
|
223
|
+
path: '/v1/quotes',
|
|
224
|
+
tag: 'Quotes',
|
|
225
|
+
summary: 'List quotes',
|
|
226
|
+
auth: 'service',
|
|
227
|
+
scope: 'payments:read',
|
|
228
|
+
query: listQuotesQuery,
|
|
229
|
+
response: listOf(quoteSchema),
|
|
230
|
+
sdk: 'quotes.list',
|
|
231
|
+
expandable: 'quote',
|
|
232
|
+
}),
|
|
233
|
+
defineRoute({
|
|
234
|
+
operationId: 'retrieveQuote',
|
|
235
|
+
method: 'get',
|
|
236
|
+
path: '/v1/quotes/{id}',
|
|
237
|
+
tag: 'Quotes',
|
|
238
|
+
summary: 'Retrieve a quote',
|
|
239
|
+
auth: 'service',
|
|
240
|
+
scope: 'payments:read',
|
|
241
|
+
params: quoteId,
|
|
242
|
+
query: expandOnlyQuery,
|
|
243
|
+
response: quoteSchema,
|
|
244
|
+
sdk: 'quotes.retrieve',
|
|
245
|
+
expandable: 'quote',
|
|
246
|
+
}),
|
|
247
|
+
defineRoute({
|
|
248
|
+
operationId: 'updateQuote',
|
|
249
|
+
method: 'post',
|
|
250
|
+
path: '/v1/quotes/{id}',
|
|
251
|
+
tag: 'Quotes',
|
|
252
|
+
summary: 'Update a quote',
|
|
253
|
+
description: 'Drafts only, except `metadata`. `line_items` replaces every line; a field sent as `""` is cleared; `metadata` is a patch.',
|
|
254
|
+
auth: 'service',
|
|
255
|
+
scope: 'payments:write',
|
|
256
|
+
idempotent: true,
|
|
257
|
+
params: quoteId,
|
|
258
|
+
body: updateQuoteParams,
|
|
259
|
+
response: quoteSchema,
|
|
260
|
+
sdk: 'quotes.update',
|
|
261
|
+
expandable: 'quote',
|
|
262
|
+
}),
|
|
263
|
+
defineRoute({
|
|
264
|
+
operationId: 'finalizeQuote',
|
|
265
|
+
method: 'post',
|
|
266
|
+
path: '/v1/quotes/{id}/finalize',
|
|
267
|
+
tag: 'Quotes',
|
|
268
|
+
summary: 'Finalize a draft quote',
|
|
269
|
+
description: 'It gets its number, its discount and its Peable Tax. Tax fails closed: a quote whose tax cannot be computed stays a draft (`automatic_tax.status` says why).',
|
|
270
|
+
auth: 'service',
|
|
271
|
+
scope: 'payments:write',
|
|
272
|
+
idempotent: true,
|
|
273
|
+
params: quoteId,
|
|
274
|
+
body: finalizeQuoteParams,
|
|
275
|
+
response: quoteSchema,
|
|
276
|
+
sdk: 'quotes.finalizeQuote',
|
|
277
|
+
expandable: 'quote',
|
|
278
|
+
}),
|
|
279
|
+
defineRoute({
|
|
280
|
+
operationId: 'acceptQuote',
|
|
281
|
+
method: 'post',
|
|
282
|
+
path: '/v1/quotes/{id}/accept',
|
|
283
|
+
tag: 'Quotes',
|
|
284
|
+
summary: 'Accept an open quote',
|
|
285
|
+
description: 'The customer said yes. One-time lines become an invoice; recurring lines a subscription whose first invoice also carries the one-time lines. The invoice is finalized (tax before finalize) and collected as the engine collects any other: charged when `charge_automatically` and the customer has a card, otherwise paid on its hosted page — where FairCoin is always offered.',
|
|
286
|
+
auth: 'service',
|
|
287
|
+
scope: 'payments:write',
|
|
288
|
+
idempotent: true,
|
|
289
|
+
params: quoteId,
|
|
290
|
+
body: quoteActionParams,
|
|
291
|
+
response: quoteSchema,
|
|
292
|
+
sdk: 'quotes.accept',
|
|
293
|
+
expandable: 'quote',
|
|
294
|
+
}),
|
|
295
|
+
defineRoute({
|
|
296
|
+
operationId: 'cancelQuote',
|
|
297
|
+
method: 'post',
|
|
298
|
+
path: '/v1/quotes/{id}/cancel',
|
|
299
|
+
tag: 'Quotes',
|
|
300
|
+
summary: 'Cancel a quote',
|
|
301
|
+
description: 'A draft or an open quote; an accepted one cannot be cancelled.',
|
|
302
|
+
auth: 'service',
|
|
303
|
+
scope: 'payments:write',
|
|
304
|
+
idempotent: true,
|
|
305
|
+
params: quoteId,
|
|
306
|
+
body: quoteActionParams,
|
|
307
|
+
response: quoteSchema,
|
|
308
|
+
sdk: 'quotes.cancel',
|
|
309
|
+
expandable: 'quote',
|
|
310
|
+
}),
|
|
311
|
+
defineRoute({
|
|
312
|
+
operationId: 'listQuoteLineItems',
|
|
313
|
+
method: 'get',
|
|
314
|
+
path: '/v1/quotes/{id}/line_items',
|
|
315
|
+
tag: 'Quotes',
|
|
316
|
+
summary: "List a quote's line items",
|
|
317
|
+
description: "In their order (at most twenty); the cursor is a line's own `li_…`.",
|
|
318
|
+
auth: 'service',
|
|
319
|
+
scope: 'payments:read',
|
|
320
|
+
params: quoteId,
|
|
321
|
+
query: listQuoteLineItemsQuery,
|
|
322
|
+
response: listOf(checkoutLineItemSchema),
|
|
323
|
+
sdk: 'quotes.listLineItems',
|
|
324
|
+
expandable: 'item',
|
|
325
|
+
}),
|
|
326
|
+
defineRoute({
|
|
327
|
+
operationId: 'retrieveQuotePdf',
|
|
328
|
+
method: 'get',
|
|
329
|
+
path: '/v1/quotes/{id}/pdf',
|
|
330
|
+
tag: 'Quotes',
|
|
331
|
+
summary: "Download a quote's PDF",
|
|
332
|
+
description: 'A draft renders marked as a draft, without a number.',
|
|
333
|
+
auth: 'service',
|
|
334
|
+
scope: 'payments:read',
|
|
335
|
+
params: quoteId,
|
|
336
|
+
response: { kind: 'binary', contentType: 'application/pdf' },
|
|
337
|
+
sdk: 'quotes.pdf',
|
|
338
|
+
}),
|
|
339
|
+
];
|
|
@@ -270,6 +270,10 @@ export const WEBHOOK_EVENT_DESCRIPTIONS = {
|
|
|
270
270
|
'billing_portal.configuration.created': 'A customer portal configuration was created.',
|
|
271
271
|
'billing_portal.configuration.updated': 'A customer portal configuration was updated.',
|
|
272
272
|
'billing_portal.session.created': 'A customer portal session was created.',
|
|
273
|
+
'quote.created': 'A draft Quote was created.',
|
|
274
|
+
'quote.finalized': 'A Quote was finalized: numbered, priced and taxed, waiting for its customer.',
|
|
275
|
+
'quote.accepted': 'A Quote was accepted: its `invoice` (and, for recurring lines, its `subscription`) exists.',
|
|
276
|
+
'quote.canceled': 'A Quote was cancelled, or expired while open.',
|
|
273
277
|
'tax.assessment.created': 'A tax compliance assessment was run. Nothing was registered, filed or collected.',
|
|
274
278
|
'tax.review_item.created': 'A tax assessment finding opened a review item.',
|
|
275
279
|
'tax.review_item.updated': 'A tax review item was decided, or found again.',
|
|
@@ -112,6 +112,9 @@ export const ERROR_CODE_DESCRIPTIONS = {
|
|
|
112
112
|
invoice_not_editable: 'The invoice is finalized and can no longer be edited.',
|
|
113
113
|
invoice_unexpected_state: 'The invoice is in a status that does not allow this operation.',
|
|
114
114
|
invoice_no_customer_line_items: 'The invoice has no line items to finalize.',
|
|
115
|
+
quote_not_editable: 'Only a draft quote can be edited.',
|
|
116
|
+
quote_unexpected_state: "The quote's status does not allow this.",
|
|
117
|
+
quote_expired: 'The quote expired.',
|
|
115
118
|
invoice_payment_intent_requires_action: "The invoice's payment needs the customer to act (a card challenge).",
|
|
116
119
|
subscription_unexpected_state: 'The subscription is in a status that does not allow this operation.',
|
|
117
120
|
customer_currency_mismatch: "The currency differs from the customer's billing currency.",
|
|
@@ -120,6 +120,10 @@ export const WEBHOOK_EVENT_OBJECTS = {
|
|
|
120
120
|
'billing_portal.configuration.created': 'billing_portal.configuration',
|
|
121
121
|
'billing_portal.configuration.updated': 'billing_portal.configuration',
|
|
122
122
|
'billing_portal.session.created': 'billing_portal.session',
|
|
123
|
+
'quote.created': 'quote',
|
|
124
|
+
'quote.finalized': 'quote',
|
|
125
|
+
'quote.accepted': 'quote',
|
|
126
|
+
'quote.canceled': 'quote',
|
|
123
127
|
'tax.assessment.created': 'tax.assessment',
|
|
124
128
|
'tax.review_item.created': 'tax.review_item',
|
|
125
129
|
'tax.review_item.updated': 'tax.review_item',
|
|
@@ -10,6 +10,9 @@ export const INVOICE_BILLING_REASONS = [
|
|
|
10
10
|
'subscription_update',
|
|
11
11
|
'subscription_cancel',
|
|
12
12
|
'upcoming',
|
|
13
|
+
// A one-time quote's invoice (Stripe's name); a recurring quote's first
|
|
14
|
+
// invoice is its subscription's `subscription_create`.
|
|
15
|
+
'quote_accept',
|
|
13
16
|
];
|
|
14
17
|
/**
|
|
15
18
|
* `automatic_tax.status` — Peable Tax (ADR 0011) is computed before an invoice
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Quotes (`qt_…`, ADR 0018 §5) — the closed value sets their schemas are built
|
|
2
|
+
// from. Zod-free: `@peable.to/shared-types` re-exports them at runtime.
|
|
3
|
+
/**
|
|
4
|
+
* Where a quote stands — Stripe's four.
|
|
5
|
+
*
|
|
6
|
+
* - `draft` — being written; the only status a quote can be edited in.
|
|
7
|
+
* - `open` — finalized: numbered, priced and taxed, waiting for the
|
|
8
|
+
* customer's answer until `expires_at`.
|
|
9
|
+
* - `accepted` — terminal: the native billing engine made its invoice (one-time
|
|
10
|
+
* lines) or its subscription and first invoice (recurring lines).
|
|
11
|
+
* - `canceled` — terminal: cancelled by the merchant, or expired while open.
|
|
12
|
+
*/
|
|
13
|
+
export const QUOTE_STATUSES = ['draft', 'open', 'accepted', 'canceled'];
|
|
14
|
+
/** Bounds a quote is checked against. */
|
|
15
|
+
export const QUOTE_LIMITS = {
|
|
16
|
+
/** Lines on one quote — a subscription's item limit. */
|
|
17
|
+
lineItemsMax: 20,
|
|
18
|
+
quantityMax: 1000000,
|
|
19
|
+
/** `header` and `footer`; `description` is 1500 like an invoice's. */
|
|
20
|
+
headerMax: 50,
|
|
21
|
+
footerMax: 500,
|
|
22
|
+
descriptionMax: 1500,
|
|
23
|
+
/** A quote expires 30 days after it is created unless `expires_at` says otherwise (Stripe's default). */
|
|
24
|
+
defaultExpiryDays: 30,
|
|
25
|
+
/** `expires_at` at most this far ahead. */
|
|
26
|
+
expiryMaxDays: 365,
|
|
27
|
+
trialPeriodDaysMax: 730,
|
|
28
|
+
};
|