@pimia/sdk 0.2.0 → 0.3.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 +57 -0
- package/dist/api.d.ts +150 -254
- package/dist/client.d.ts +382 -11
- package/dist/client.js +27 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/webhooks.d.ts +305 -0
- package/dist/webhooks.js +230 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -13,8 +13,42 @@
|
|
|
13
13
|
* - **429**: respeta `Retry-After` y reintenta con espera acotada;
|
|
14
14
|
* - **errores tipados**: MissingScopeError trae el scope exacto que falta.
|
|
15
15
|
*/
|
|
16
|
+
import type { components } from './api.js';
|
|
16
17
|
import { OAuth, type OAuthConfig } from './oauth.js';
|
|
17
18
|
import { type TokenStore } from './tokens.js';
|
|
19
|
+
type Schemas = components['schemas'];
|
|
20
|
+
/** Cliente tal y como lo devuelve la API. */
|
|
21
|
+
export type CustomerResource = Schemas['CustomerResource'];
|
|
22
|
+
/** Factura tal y como la devuelve la API. */
|
|
23
|
+
export type InvoiceResource = Schemas['InvoiceResource'];
|
|
24
|
+
/** Presupuesto tal y como lo devuelve la API. */
|
|
25
|
+
export type EstimateResource = Schemas['EstimateResource'];
|
|
26
|
+
/** Cuerpo de alta/edición de cliente. Incluye `customFields`. */
|
|
27
|
+
export type CustomerRequest = Schemas['CustomerRequest'];
|
|
28
|
+
/** Cuerpo de alta/edición de factura. Incluye `customFields`. */
|
|
29
|
+
export type InvoicesRequest = Schemas['InvoicesRequest'];
|
|
30
|
+
/** Cuerpo de alta/edición de presupuesto. Incluye `customFields`. */
|
|
31
|
+
export type EstimatesRequest = Schemas['EstimatesRequest'];
|
|
32
|
+
/**
|
|
33
|
+
* El sobre `{ data: … }` de Laravel para las escrituras que el spec **no
|
|
34
|
+
* tipa**.
|
|
35
|
+
*
|
|
36
|
+
* Hay 17 operaciones cuyo `200` sale del generador como objeto vacío, y entre
|
|
37
|
+
* ellas están `POST /invoices`, `PUT /invoices/{id}`, `PUT /customers/{id}` y
|
|
38
|
+
* `POST /estimates/{id}/convert-to-invoice`. Usar ahí el tipo generado sería
|
|
39
|
+
* peor que no tipar: `Record<string, never>` afirma que la respuesta **no
|
|
40
|
+
* tiene propiedades**, y el `data` real desaparecería del autocompletado.
|
|
41
|
+
*
|
|
42
|
+
* Así que el sobre se declara aquí y el recurso de dentro sí sale del spec.
|
|
43
|
+
* Está verificado contra los controladores del core, no supuesto: los cuatro
|
|
44
|
+
* devuelven `new XResource($modelo)` con el envoltorio `data` de Laravel
|
|
45
|
+
* activo. La causa del hueco es del generador —un `@return JsonResponse`
|
|
46
|
+
* heredado que le gana a la inferencia—, no del contrato; cuando se arregle
|
|
47
|
+
* en el core, estos tipos pasarán a salir de `Ok<…>` como los demás.
|
|
48
|
+
*/
|
|
49
|
+
export interface ResourceEnvelope<T> {
|
|
50
|
+
data: T;
|
|
51
|
+
}
|
|
18
52
|
export interface PimiaClientOptions extends OAuthConfig {
|
|
19
53
|
tokens: TokenStore;
|
|
20
54
|
/** Segundos de margen para refrescar antes de que caduque (default 60). */
|
|
@@ -94,21 +128,357 @@ export declare class PimiaClient {
|
|
|
94
128
|
/** Cabeceras `X-RateLimit-*` de la última respuesta. */
|
|
95
129
|
get rateLimit(): RateLimit;
|
|
96
130
|
get invoices(): {
|
|
97
|
-
list: (query?: RequestOptions["query"]) => Promise<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
131
|
+
list: (query?: RequestOptions["query"]) => Promise<{
|
|
132
|
+
data: components["schemas"]["InvoiceResource"][];
|
|
133
|
+
meta: {
|
|
134
|
+
invoice_total_count: number;
|
|
135
|
+
};
|
|
136
|
+
}>;
|
|
137
|
+
get: (id: number | string) => Promise<{
|
|
138
|
+
data: components["schemas"]["InvoiceResource"] & Record<string, never>;
|
|
139
|
+
}>;
|
|
140
|
+
/**
|
|
141
|
+
* Devuelve `{ data: InvoiceResource }`. El tipo NO sale del spec: el
|
|
142
|
+
* `200` de `invoices.store` está vacío ahí (ver {@link ResourceEnvelope}).
|
|
143
|
+
*/
|
|
144
|
+
create: (body: InvoicesRequest, options?: WriteOptions) => Promise<ResourceEnvelope<{
|
|
145
|
+
id: string;
|
|
146
|
+
invoice_date: string;
|
|
147
|
+
due_date: string;
|
|
148
|
+
invoice_number: string;
|
|
149
|
+
reference_number: string;
|
|
150
|
+
status: string;
|
|
151
|
+
paid_status: string;
|
|
152
|
+
tax_per_item: string;
|
|
153
|
+
tax_included: string;
|
|
154
|
+
discount_per_item: string;
|
|
155
|
+
notes: string;
|
|
156
|
+
discount_type: string;
|
|
157
|
+
discount: string;
|
|
158
|
+
discount_val: string;
|
|
159
|
+
sub_total: string;
|
|
160
|
+
total: string;
|
|
161
|
+
effective_total: string;
|
|
162
|
+
tax: string;
|
|
163
|
+
due_amount: string;
|
|
164
|
+
effective_due_amount: string;
|
|
165
|
+
sent: string;
|
|
166
|
+
viewed: string;
|
|
167
|
+
unique_hash: string;
|
|
168
|
+
template_name: string;
|
|
169
|
+
invoice_series_id: string;
|
|
170
|
+
customer_id: string;
|
|
171
|
+
payment_method_id: string;
|
|
172
|
+
recurring_invoice_id: string;
|
|
173
|
+
sequence_number: string;
|
|
174
|
+
exchange_rate: string;
|
|
175
|
+
base_discount_val: string;
|
|
176
|
+
base_sub_total: string;
|
|
177
|
+
base_total: string;
|
|
178
|
+
creator_id: string;
|
|
179
|
+
base_tax: string;
|
|
180
|
+
base_due_amount: string;
|
|
181
|
+
effective_base_total: string;
|
|
182
|
+
effective_base_due_amount: string;
|
|
183
|
+
credited_total: string;
|
|
184
|
+
credited_base_total: string;
|
|
185
|
+
currency_id: string;
|
|
186
|
+
formatted_created_at: string;
|
|
187
|
+
invoice_pdf_url: string;
|
|
188
|
+
formatted_invoice_date: string;
|
|
189
|
+
formatted_due_date: string;
|
|
190
|
+
allow_edit: string;
|
|
191
|
+
payment_module_enabled: string;
|
|
192
|
+
sales_tax_type: string;
|
|
193
|
+
sales_tax_address_type: string;
|
|
194
|
+
overdue: string;
|
|
195
|
+
effective_paid_status: string;
|
|
196
|
+
effective_overdue: string;
|
|
197
|
+
aeat_status: string;
|
|
198
|
+
qr_data: string;
|
|
199
|
+
hash: string;
|
|
200
|
+
aeat_csv: string;
|
|
201
|
+
is_credit_note: string | boolean;
|
|
202
|
+
rectified_invoice_id: string;
|
|
203
|
+
rectified_invoice_number?: string | null;
|
|
204
|
+
rectified_invoice?: {
|
|
205
|
+
id: string;
|
|
206
|
+
invoice_number: string;
|
|
207
|
+
tax_per_item: string;
|
|
208
|
+
tax_included: string;
|
|
209
|
+
sub_total: string;
|
|
210
|
+
discount_val: string;
|
|
211
|
+
tax: string;
|
|
212
|
+
total: string;
|
|
213
|
+
items: components["schemas"]["InvoiceItemResource"][];
|
|
214
|
+
taxes: components["schemas"]["TaxResource"][];
|
|
215
|
+
};
|
|
216
|
+
credit_notes_count: number;
|
|
217
|
+
items?: components["schemas"]["InvoiceItemResource"][];
|
|
218
|
+
payments?: components["schemas"]["PaymentResource"][];
|
|
219
|
+
customer?: components["schemas"]["CustomerResource"];
|
|
220
|
+
invoice_series?: components["schemas"]["InvoiceSeriesResource"];
|
|
221
|
+
payment_method?: components["schemas"]["PaymentMethodResource"];
|
|
222
|
+
creator?: components["schemas"]["UserResource"];
|
|
223
|
+
taxes: components["schemas"]["TaxResource"][];
|
|
224
|
+
fields?: components["schemas"]["CustomFieldValueResource"][];
|
|
225
|
+
company?: components["schemas"]["CompanyResource"];
|
|
226
|
+
currency?: components["schemas"]["CurrencyResource"];
|
|
227
|
+
}>>;
|
|
228
|
+
/** Mismo caso que `create`: el `200` de `invoices.update` no está tipado en el spec. */
|
|
229
|
+
update: (id: number | string, body: InvoicesRequest, options?: WriteOptions) => Promise<ResourceEnvelope<{
|
|
230
|
+
id: string;
|
|
231
|
+
invoice_date: string;
|
|
232
|
+
due_date: string;
|
|
233
|
+
invoice_number: string;
|
|
234
|
+
reference_number: string;
|
|
235
|
+
status: string;
|
|
236
|
+
paid_status: string;
|
|
237
|
+
tax_per_item: string;
|
|
238
|
+
tax_included: string;
|
|
239
|
+
discount_per_item: string;
|
|
240
|
+
notes: string;
|
|
241
|
+
discount_type: string;
|
|
242
|
+
discount: string;
|
|
243
|
+
discount_val: string;
|
|
244
|
+
sub_total: string;
|
|
245
|
+
total: string;
|
|
246
|
+
effective_total: string;
|
|
247
|
+
tax: string;
|
|
248
|
+
due_amount: string;
|
|
249
|
+
effective_due_amount: string;
|
|
250
|
+
sent: string;
|
|
251
|
+
viewed: string;
|
|
252
|
+
unique_hash: string;
|
|
253
|
+
template_name: string;
|
|
254
|
+
invoice_series_id: string;
|
|
255
|
+
customer_id: string;
|
|
256
|
+
payment_method_id: string;
|
|
257
|
+
recurring_invoice_id: string;
|
|
258
|
+
sequence_number: string;
|
|
259
|
+
exchange_rate: string;
|
|
260
|
+
base_discount_val: string;
|
|
261
|
+
base_sub_total: string;
|
|
262
|
+
base_total: string;
|
|
263
|
+
creator_id: string;
|
|
264
|
+
base_tax: string;
|
|
265
|
+
base_due_amount: string;
|
|
266
|
+
effective_base_total: string;
|
|
267
|
+
effective_base_due_amount: string;
|
|
268
|
+
credited_total: string;
|
|
269
|
+
credited_base_total: string;
|
|
270
|
+
currency_id: string;
|
|
271
|
+
formatted_created_at: string;
|
|
272
|
+
invoice_pdf_url: string;
|
|
273
|
+
formatted_invoice_date: string;
|
|
274
|
+
formatted_due_date: string;
|
|
275
|
+
allow_edit: string;
|
|
276
|
+
payment_module_enabled: string;
|
|
277
|
+
sales_tax_type: string;
|
|
278
|
+
sales_tax_address_type: string;
|
|
279
|
+
overdue: string;
|
|
280
|
+
effective_paid_status: string;
|
|
281
|
+
effective_overdue: string;
|
|
282
|
+
aeat_status: string;
|
|
283
|
+
qr_data: string;
|
|
284
|
+
hash: string;
|
|
285
|
+
aeat_csv: string;
|
|
286
|
+
is_credit_note: string | boolean;
|
|
287
|
+
rectified_invoice_id: string;
|
|
288
|
+
rectified_invoice_number?: string | null;
|
|
289
|
+
rectified_invoice?: {
|
|
290
|
+
id: string;
|
|
291
|
+
invoice_number: string;
|
|
292
|
+
tax_per_item: string;
|
|
293
|
+
tax_included: string;
|
|
294
|
+
sub_total: string;
|
|
295
|
+
discount_val: string;
|
|
296
|
+
tax: string;
|
|
297
|
+
total: string;
|
|
298
|
+
items: components["schemas"]["InvoiceItemResource"][];
|
|
299
|
+
taxes: components["schemas"]["TaxResource"][];
|
|
300
|
+
};
|
|
301
|
+
credit_notes_count: number;
|
|
302
|
+
items?: components["schemas"]["InvoiceItemResource"][];
|
|
303
|
+
payments?: components["schemas"]["PaymentResource"][];
|
|
304
|
+
customer?: components["schemas"]["CustomerResource"];
|
|
305
|
+
invoice_series?: components["schemas"]["InvoiceSeriesResource"];
|
|
306
|
+
payment_method?: components["schemas"]["PaymentMethodResource"];
|
|
307
|
+
creator?: components["schemas"]["UserResource"];
|
|
308
|
+
taxes: components["schemas"]["TaxResource"][];
|
|
309
|
+
fields?: components["schemas"]["CustomFieldValueResource"][];
|
|
310
|
+
company?: components["schemas"]["CompanyResource"];
|
|
311
|
+
currency?: components["schemas"]["CurrencyResource"];
|
|
312
|
+
}>>;
|
|
101
313
|
};
|
|
102
314
|
get customers(): {
|
|
103
|
-
list: (query?: RequestOptions["query"]) => Promise<
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
315
|
+
list: (query?: RequestOptions["query"]) => Promise<{
|
|
316
|
+
data: components["schemas"]["CustomerResource"][];
|
|
317
|
+
meta: {
|
|
318
|
+
customer_total_count: number;
|
|
319
|
+
};
|
|
320
|
+
}>;
|
|
321
|
+
get: (id: number | string) => Promise<{
|
|
322
|
+
data: components["schemas"]["CustomerResource"];
|
|
323
|
+
}>;
|
|
324
|
+
create: (body: CustomerRequest, options?: WriteOptions) => Promise<{
|
|
325
|
+
data: components["schemas"]["CustomerResource"];
|
|
326
|
+
}>;
|
|
327
|
+
/** El `200` de `customers.update` no está tipado en el spec. */
|
|
328
|
+
update: (id: number | string, body: CustomerRequest, options?: WriteOptions) => Promise<ResourceEnvelope<{
|
|
329
|
+
id: string;
|
|
330
|
+
name: string;
|
|
331
|
+
email: string;
|
|
332
|
+
phone: string;
|
|
333
|
+
contact_name: string;
|
|
334
|
+
company_name: string;
|
|
335
|
+
website: string;
|
|
336
|
+
enable_portal: string;
|
|
337
|
+
password_added: boolean;
|
|
338
|
+
currency_id: string;
|
|
339
|
+
payment_method_id: string;
|
|
340
|
+
company_id: string;
|
|
341
|
+
facebook_id: string;
|
|
342
|
+
google_id: string;
|
|
343
|
+
github_id: string;
|
|
344
|
+
created_at: string;
|
|
345
|
+
formatted_created_at: string;
|
|
346
|
+
updated_at: string;
|
|
347
|
+
avatar: string;
|
|
348
|
+
due_amount: string;
|
|
349
|
+
base_due_amount: string;
|
|
350
|
+
prefix: string;
|
|
351
|
+
tax_id: string;
|
|
352
|
+
notes: string;
|
|
353
|
+
iban: string;
|
|
354
|
+
bic: string;
|
|
355
|
+
sepa_mandate_id: string;
|
|
356
|
+
sepa_mandate_date: string;
|
|
357
|
+
billing?: components["schemas"]["AddressResource"];
|
|
358
|
+
shipping?: components["schemas"]["AddressResource"];
|
|
359
|
+
fields?: components["schemas"]["CustomFieldValueResource"][];
|
|
360
|
+
company?: components["schemas"]["CompanyResource"];
|
|
361
|
+
currency?: components["schemas"]["CurrencyResource"];
|
|
362
|
+
payment_method?: components["schemas"]["PaymentMethodResource"];
|
|
363
|
+
}>>;
|
|
107
364
|
};
|
|
108
365
|
get estimates(): {
|
|
109
|
-
list: (query?: RequestOptions["query"]) => Promise<
|
|
110
|
-
|
|
111
|
-
|
|
366
|
+
list: (query?: RequestOptions["query"]) => Promise<{
|
|
367
|
+
data: components["schemas"]["EstimateResource"][];
|
|
368
|
+
meta: {
|
|
369
|
+
estimate_total_count: number;
|
|
370
|
+
};
|
|
371
|
+
}>;
|
|
372
|
+
get: (id: number | string) => Promise<{
|
|
373
|
+
data: components["schemas"]["EstimateResource"];
|
|
374
|
+
}>;
|
|
375
|
+
create: (body: EstimatesRequest, options?: WriteOptions) => Promise<{
|
|
376
|
+
data: components["schemas"]["EstimateResource"];
|
|
377
|
+
}>;
|
|
378
|
+
/**
|
|
379
|
+
* Convierte un presupuesto aceptado en factura.
|
|
380
|
+
*
|
|
381
|
+
* El helper existe porque es el cierre natural del bucle
|
|
382
|
+
* `estimate.accepted` → facturar, y sin él hay que ir por ruta cruda y
|
|
383
|
+
* adivinar la forma de la respuesta.
|
|
384
|
+
*
|
|
385
|
+
* Dos cosas que conviene saber y que el spec no dice:
|
|
386
|
+
*
|
|
387
|
+
* - **la factura nace BORRADOR y sin numerar**: `data.invoice_number` es
|
|
388
|
+
* `null` hasta que la publiques cambiando su estado. No es un fallo;
|
|
389
|
+
* - el id de la factura nueva está en `data.id`. El `r?.data?.id ?? r?.id`
|
|
390
|
+
* defensivo que se ve por ahí sobra: la segunda rama nunca ocurre.
|
|
391
|
+
*
|
|
392
|
+
* Manda `idempotencyKey` —una clave estable por presupuesto, del estilo
|
|
393
|
+
* `estimate:{id}:invoice`— y el reintento tras un timeout no te creará
|
|
394
|
+
* una segunda factura.
|
|
395
|
+
*
|
|
396
|
+
* Exige `estimates:write` **e** `invoices:write`.
|
|
397
|
+
*/
|
|
398
|
+
convertToInvoice: (id: number | string, options?: WriteOptions) => Promise<ResourceEnvelope<{
|
|
399
|
+
id: string;
|
|
400
|
+
invoice_date: string;
|
|
401
|
+
due_date: string;
|
|
402
|
+
invoice_number: string;
|
|
403
|
+
reference_number: string;
|
|
404
|
+
status: string;
|
|
405
|
+
paid_status: string;
|
|
406
|
+
tax_per_item: string;
|
|
407
|
+
tax_included: string;
|
|
408
|
+
discount_per_item: string;
|
|
409
|
+
notes: string;
|
|
410
|
+
discount_type: string;
|
|
411
|
+
discount: string;
|
|
412
|
+
discount_val: string;
|
|
413
|
+
sub_total: string;
|
|
414
|
+
total: string;
|
|
415
|
+
effective_total: string;
|
|
416
|
+
tax: string;
|
|
417
|
+
due_amount: string;
|
|
418
|
+
effective_due_amount: string;
|
|
419
|
+
sent: string;
|
|
420
|
+
viewed: string;
|
|
421
|
+
unique_hash: string;
|
|
422
|
+
template_name: string;
|
|
423
|
+
invoice_series_id: string;
|
|
424
|
+
customer_id: string;
|
|
425
|
+
payment_method_id: string;
|
|
426
|
+
recurring_invoice_id: string;
|
|
427
|
+
sequence_number: string;
|
|
428
|
+
exchange_rate: string;
|
|
429
|
+
base_discount_val: string;
|
|
430
|
+
base_sub_total: string;
|
|
431
|
+
base_total: string;
|
|
432
|
+
creator_id: string;
|
|
433
|
+
base_tax: string;
|
|
434
|
+
base_due_amount: string;
|
|
435
|
+
effective_base_total: string;
|
|
436
|
+
effective_base_due_amount: string;
|
|
437
|
+
credited_total: string;
|
|
438
|
+
credited_base_total: string;
|
|
439
|
+
currency_id: string;
|
|
440
|
+
formatted_created_at: string;
|
|
441
|
+
invoice_pdf_url: string;
|
|
442
|
+
formatted_invoice_date: string;
|
|
443
|
+
formatted_due_date: string;
|
|
444
|
+
allow_edit: string;
|
|
445
|
+
payment_module_enabled: string;
|
|
446
|
+
sales_tax_type: string;
|
|
447
|
+
sales_tax_address_type: string;
|
|
448
|
+
overdue: string;
|
|
449
|
+
effective_paid_status: string;
|
|
450
|
+
effective_overdue: string;
|
|
451
|
+
aeat_status: string;
|
|
452
|
+
qr_data: string;
|
|
453
|
+
hash: string;
|
|
454
|
+
aeat_csv: string;
|
|
455
|
+
is_credit_note: string | boolean;
|
|
456
|
+
rectified_invoice_id: string;
|
|
457
|
+
rectified_invoice_number?: string | null;
|
|
458
|
+
rectified_invoice?: {
|
|
459
|
+
id: string;
|
|
460
|
+
invoice_number: string;
|
|
461
|
+
tax_per_item: string;
|
|
462
|
+
tax_included: string;
|
|
463
|
+
sub_total: string;
|
|
464
|
+
discount_val: string;
|
|
465
|
+
tax: string;
|
|
466
|
+
total: string;
|
|
467
|
+
items: components["schemas"]["InvoiceItemResource"][];
|
|
468
|
+
taxes: components["schemas"]["TaxResource"][];
|
|
469
|
+
};
|
|
470
|
+
credit_notes_count: number;
|
|
471
|
+
items?: components["schemas"]["InvoiceItemResource"][];
|
|
472
|
+
payments?: components["schemas"]["PaymentResource"][];
|
|
473
|
+
customer?: components["schemas"]["CustomerResource"];
|
|
474
|
+
invoice_series?: components["schemas"]["InvoiceSeriesResource"];
|
|
475
|
+
payment_method?: components["schemas"]["PaymentMethodResource"];
|
|
476
|
+
creator?: components["schemas"]["UserResource"];
|
|
477
|
+
taxes: components["schemas"]["TaxResource"][];
|
|
478
|
+
fields?: components["schemas"]["CustomFieldValueResource"][];
|
|
479
|
+
company?: components["schemas"]["CompanyResource"];
|
|
480
|
+
currency?: components["schemas"]["CurrencyResource"];
|
|
481
|
+
}>>;
|
|
112
482
|
};
|
|
113
483
|
get<T = unknown>(path: string, query?: RequestOptions['query']): Promise<T>;
|
|
114
484
|
post<T = unknown>(path: string, body?: unknown, options?: WriteOptions): Promise<T>;
|
|
@@ -149,3 +519,4 @@ export declare class PimiaClient {
|
|
|
149
519
|
private captureRateLimit;
|
|
150
520
|
private retryDelay;
|
|
151
521
|
}
|
|
522
|
+
export {};
|
package/dist/client.js
CHANGED
|
@@ -46,7 +46,12 @@ export class PimiaClient {
|
|
|
46
46
|
return {
|
|
47
47
|
list: (query) => this.get('/invoices', query),
|
|
48
48
|
get: (id) => this.get(`/invoices/${id}`),
|
|
49
|
+
/**
|
|
50
|
+
* Devuelve `{ data: InvoiceResource }`. El tipo NO sale del spec: el
|
|
51
|
+
* `200` de `invoices.store` está vacío ahí (ver {@link ResourceEnvelope}).
|
|
52
|
+
*/
|
|
49
53
|
create: (body, options) => this.post('/invoices', body, options),
|
|
54
|
+
/** Mismo caso que `create`: el `200` de `invoices.update` no está tipado en el spec. */
|
|
50
55
|
update: (id, body, options) => this.put(`/invoices/${id}`, body, options),
|
|
51
56
|
};
|
|
52
57
|
}
|
|
@@ -55,6 +60,7 @@ export class PimiaClient {
|
|
|
55
60
|
list: (query) => this.get('/customers', query),
|
|
56
61
|
get: (id) => this.get(`/customers/${id}`),
|
|
57
62
|
create: (body, options) => this.post('/customers', body, options),
|
|
63
|
+
/** El `200` de `customers.update` no está tipado en el spec. */
|
|
58
64
|
update: (id, body, options) => this.put(`/customers/${id}`, body, options),
|
|
59
65
|
};
|
|
60
66
|
}
|
|
@@ -63,6 +69,27 @@ export class PimiaClient {
|
|
|
63
69
|
list: (query) => this.get('/estimates', query),
|
|
64
70
|
get: (id) => this.get(`/estimates/${id}`),
|
|
65
71
|
create: (body, options) => this.post('/estimates', body, options),
|
|
72
|
+
/**
|
|
73
|
+
* Convierte un presupuesto aceptado en factura.
|
|
74
|
+
*
|
|
75
|
+
* El helper existe porque es el cierre natural del bucle
|
|
76
|
+
* `estimate.accepted` → facturar, y sin él hay que ir por ruta cruda y
|
|
77
|
+
* adivinar la forma de la respuesta.
|
|
78
|
+
*
|
|
79
|
+
* Dos cosas que conviene saber y que el spec no dice:
|
|
80
|
+
*
|
|
81
|
+
* - **la factura nace BORRADOR y sin numerar**: `data.invoice_number` es
|
|
82
|
+
* `null` hasta que la publiques cambiando su estado. No es un fallo;
|
|
83
|
+
* - el id de la factura nueva está en `data.id`. El `r?.data?.id ?? r?.id`
|
|
84
|
+
* defensivo que se ve por ahí sobra: la segunda rama nunca ocurre.
|
|
85
|
+
*
|
|
86
|
+
* Manda `idempotencyKey` —una clave estable por presupuesto, del estilo
|
|
87
|
+
* `estimate:{id}:invoice`— y el reintento tras un timeout no te creará
|
|
88
|
+
* una segunda factura.
|
|
89
|
+
*
|
|
90
|
+
* Exige `estimates:write` **e** `invoices:write`.
|
|
91
|
+
*/
|
|
92
|
+
convertToInvoice: (id, options) => this.post(`/estimates/${id}/convert-to-invoice`, {}, options),
|
|
66
93
|
};
|
|
67
94
|
}
|
|
68
95
|
get(path, query) {
|
package/dist/index.d.ts
CHANGED
|
@@ -6,12 +6,14 @@
|
|
|
6
6
|
* salen los tipos de `./api`.
|
|
7
7
|
*/
|
|
8
8
|
export { PimiaClient } from './client.js';
|
|
9
|
-
export type { PimiaClientOptions, RateLimit, RequestOptions, ResponseMeta, ResponseWithMeta, WriteOptions, } from './client.js';
|
|
9
|
+
export type { CustomerRequest, CustomerResource, EstimateResource, EstimatesRequest, InvoiceResource, InvoicesRequest, PimiaClientOptions, RateLimit, RequestOptions, ResourceEnvelope, ResponseMeta, ResponseWithMeta, WriteOptions, } from './client.js';
|
|
10
10
|
export { OAuth, createPkceChallenge, createState } from './oauth.js';
|
|
11
11
|
export type { AuthorizationServerMetadata, AuthorizeUrlOptions, OAuthConfig, PkceChallenge, } from './oauth.js';
|
|
12
12
|
export { MemoryTokenStore, isExpired, tokenSetFromResponse } from './tokens.js';
|
|
13
13
|
export type { TokenSet, TokenStore } from './tokens.js';
|
|
14
14
|
export { ForbiddenError, MissingScopeError, NotAuthenticatedError, NotFoundError, OAuthError, PimiaApiError, PimiaError, RateLimitError, UnauthorizedError, ValidationError, } from './errors.js';
|
|
15
|
+
export { WEBHOOK_DEFAULT_TOLERANCE_SECONDS, WEBHOOK_EVENTS, WEBHOOK_HEADERS, WEBHOOK_SIGNATURE_VERSION, WebhookVerificationError, isWebhookEvent, signWebhook, verifyWebhook, } from './webhooks.js';
|
|
16
|
+
export type { ApprovalDecidedPayload, AppRevokedPayload, CustomerPayload, EstimateAcceptedPayload, InvoiceCreatedPayload, InvoicePaidPayload, InvoiceReceivedPayload, IsoDateTime, KnownWebhook, PimiaWebhook, SignWebhookOptions, UnknownWebhook, VerifyWebhookOptions, WebhookBodyInput, WebhookEvent, WebhookHeadersInput, WebhookPayloads, WebhookVerificationReason, } from './webhooks.js';
|
|
15
17
|
/** Scopes granulares del catálogo de Pimia (paso 4). Pide siempre lo mínimo. */
|
|
16
18
|
export declare const SCOPES: {
|
|
17
19
|
readonly invoicesRead: "invoices:read";
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { PimiaClient } from './client.js';
|
|
|
9
9
|
export { OAuth, createPkceChallenge, createState } from './oauth.js';
|
|
10
10
|
export { MemoryTokenStore, isExpired, tokenSetFromResponse } from './tokens.js';
|
|
11
11
|
export { ForbiddenError, MissingScopeError, NotAuthenticatedError, NotFoundError, OAuthError, PimiaApiError, PimiaError, RateLimitError, UnauthorizedError, ValidationError, } from './errors.js';
|
|
12
|
+
export { WEBHOOK_DEFAULT_TOLERANCE_SECONDS, WEBHOOK_EVENTS, WEBHOOK_HEADERS, WEBHOOK_SIGNATURE_VERSION, WebhookVerificationError, isWebhookEvent, signWebhook, verifyWebhook, } from './webhooks.js';
|
|
12
13
|
/** Scopes granulares del catálogo de Pimia (paso 4). Pide siempre lo mínimo. */
|
|
13
14
|
export const SCOPES = {
|
|
14
15
|
invoicesRead: 'invoices:read',
|