@scell/sdk 1.0.0 → 1.4.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 +134 -5
- package/dist/index.d.mts +2502 -170
- package/dist/index.d.ts +2502 -170
- package/dist/index.js +1497 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1497 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +79 -1
- package/src/index.ts +17 -1
- package/src/resources/billing.ts +49 -0
- package/src/resources/fiscal.ts +128 -0
- package/src/resources/invoices.ts +217 -0
- package/src/resources/stats.ts +29 -0
- package/src/resources/sub-tenants.ts +41 -0
- package/src/resources/tenant-credit-notes.ts +301 -0
- package/src/resources/tenant-direct-credit-notes.ts +360 -0
- package/src/resources/tenant-direct-invoices.ts +424 -0
- package/src/resources/tenant-incoming-invoices.ts +429 -0
- package/src/tenant-client.ts +105 -0
- package/src/types/billing.ts +73 -0
- package/src/types/fiscal.ts +251 -0
- package/src/types/index.ts +112 -0
- package/src/types/invoices.ts +91 -0
- package/src/types/stats.ts +37 -0
- package/src/types/sub-tenants.ts +57 -0
- package/src/types/tenant-credit-notes.ts +128 -0
- package/src/types/tenant-invoices.ts +390 -0
- package/src/types/tenant-profile.ts +51 -0
- package/src/types/webhooks.ts +30 -1
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { withRetry, type RetryOptions } from './utils/retry.js';
|
|
|
14
14
|
/**
|
|
15
15
|
* Authentication mode
|
|
16
16
|
*/
|
|
17
|
-
export type AuthMode = 'bearer' | 'api-key';
|
|
17
|
+
export type AuthMode = 'bearer' | 'api-key' | 'tenant-key';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Client configuration options
|
|
@@ -116,6 +116,8 @@ export class HttpClient {
|
|
|
116
116
|
|
|
117
117
|
if (this.authMode === 'bearer') {
|
|
118
118
|
headers['Authorization'] = `Bearer ${this.authToken}`;
|
|
119
|
+
} else if (this.authMode === 'tenant-key') {
|
|
120
|
+
headers['X-Tenant-Key'] = this.authToken;
|
|
119
121
|
} else {
|
|
120
122
|
headers['X-API-Key'] = this.authToken;
|
|
121
123
|
}
|
|
@@ -294,4 +296,80 @@ export class HttpClient {
|
|
|
294
296
|
...options,
|
|
295
297
|
});
|
|
296
298
|
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* GET request that returns raw binary data as ArrayBuffer
|
|
302
|
+
*
|
|
303
|
+
* Use this for downloading files (PDF, XML, etc.)
|
|
304
|
+
*
|
|
305
|
+
* @param path - API endpoint path
|
|
306
|
+
* @param query - Query parameters
|
|
307
|
+
* @param options - Request options
|
|
308
|
+
* @returns ArrayBuffer containing the file content
|
|
309
|
+
*/
|
|
310
|
+
async getRaw(
|
|
311
|
+
path: string,
|
|
312
|
+
query?: Record<string, string | number | boolean | undefined>,
|
|
313
|
+
options?: RequestOptions
|
|
314
|
+
): Promise<ArrayBuffer> {
|
|
315
|
+
const url = this.buildUrl(path, query);
|
|
316
|
+
const requestHeaders = this.buildHeaders(options?.headers);
|
|
317
|
+
const requestTimeout = options?.timeout ?? this.timeout;
|
|
318
|
+
|
|
319
|
+
// Remove JSON content-type for raw requests
|
|
320
|
+
delete requestHeaders['Content-Type'];
|
|
321
|
+
requestHeaders['Accept'] = '*/*';
|
|
322
|
+
|
|
323
|
+
const controller = new AbortController();
|
|
324
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
|
|
325
|
+
|
|
326
|
+
if (options?.signal) {
|
|
327
|
+
options.signal.addEventListener('abort', () => controller.abort());
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
const response = await this.fetchFn(url, {
|
|
332
|
+
method: 'GET',
|
|
333
|
+
headers: requestHeaders,
|
|
334
|
+
signal: controller.signal,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
clearTimeout(timeoutId);
|
|
338
|
+
|
|
339
|
+
if (!response.ok) {
|
|
340
|
+
// Try to parse error as JSON
|
|
341
|
+
const contentType = response.headers.get('Content-Type') ?? '';
|
|
342
|
+
let responseBody: unknown;
|
|
343
|
+
|
|
344
|
+
if (contentType.includes('application/json')) {
|
|
345
|
+
responseBody = await response.json();
|
|
346
|
+
} else {
|
|
347
|
+
responseBody = await response.text();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
parseApiError(response.status, responseBody, response.headers);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return response.arrayBuffer();
|
|
354
|
+
} catch (error) {
|
|
355
|
+
clearTimeout(timeoutId);
|
|
356
|
+
|
|
357
|
+
if (error instanceof Error) {
|
|
358
|
+
if (error.name === 'AbortError') {
|
|
359
|
+
throw new ScellTimeoutError(
|
|
360
|
+
`Request timed out after ${requestTimeout}ms`
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (
|
|
365
|
+
error.name === 'TypeError' &&
|
|
366
|
+
error.message.includes('fetch')
|
|
367
|
+
) {
|
|
368
|
+
throw new ScellNetworkError('Network request failed', error);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
297
375
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
7
|
* ```typescript
|
|
8
|
-
* import { ScellClient, ScellApiClient, ScellAuth, ScellWebhooks } from '@scell/sdk';
|
|
8
|
+
* import { ScellClient, ScellApiClient, ScellTenantClient, ScellAuth, ScellWebhooks } from '@scell/sdk';
|
|
9
9
|
*
|
|
10
10
|
* // Dashboard client (Bearer token)
|
|
11
11
|
* const auth = await ScellAuth.login({ email, password });
|
|
@@ -14,9 +14,15 @@
|
|
|
14
14
|
* // API client (X-API-Key)
|
|
15
15
|
* const apiClient = new ScellApiClient('your-api-key');
|
|
16
16
|
*
|
|
17
|
+
* // Tenant client (X-Tenant-Key) - for multi-tenant operations
|
|
18
|
+
* const tenantClient = new ScellTenantClient('your-tenant-key');
|
|
19
|
+
*
|
|
17
20
|
* // Create invoice
|
|
18
21
|
* const invoice = await apiClient.invoices.create({...});
|
|
19
22
|
*
|
|
23
|
+
* // Create direct invoice (tenant)
|
|
24
|
+
* const directInvoice = await tenantClient.directInvoices.create({...});
|
|
25
|
+
*
|
|
20
26
|
* // Verify webhook
|
|
21
27
|
* const isValid = await ScellWebhooks.verifySignature(payload, signature, secret);
|
|
22
28
|
* ```
|
|
@@ -25,6 +31,9 @@
|
|
|
25
31
|
// Client
|
|
26
32
|
import { HttpClient, type ClientConfig } from './client.js';
|
|
27
33
|
|
|
34
|
+
// Tenant Client
|
|
35
|
+
import { ScellTenantClient } from './tenant-client.js';
|
|
36
|
+
|
|
28
37
|
// Resources
|
|
29
38
|
import { ApiKeysResource } from './resources/api-keys.js';
|
|
30
39
|
import { AuthResource, ScellAuth } from './resources/auth.js';
|
|
@@ -32,6 +41,7 @@ import { BalanceResource } from './resources/balance.js';
|
|
|
32
41
|
import { CompaniesResource } from './resources/companies.js';
|
|
33
42
|
import { InvoicesResource } from './resources/invoices.js';
|
|
34
43
|
import { SignaturesResource } from './resources/signatures.js';
|
|
44
|
+
import { TenantCreditNotesResource } from './resources/tenant-credit-notes.js';
|
|
35
45
|
import { WebhooksResource } from './resources/webhooks.js';
|
|
36
46
|
|
|
37
47
|
// Utilities
|
|
@@ -143,6 +153,8 @@ export class ScellApiClient {
|
|
|
143
153
|
public readonly invoices: InvoicesResource;
|
|
144
154
|
/** Signature operations (create, download, remind, cancel) */
|
|
145
155
|
public readonly signatures: SignaturesResource;
|
|
156
|
+
/** Tenant credit notes operations (create, send, download) */
|
|
157
|
+
public readonly tenantCreditNotes: TenantCreditNotesResource;
|
|
146
158
|
|
|
147
159
|
/**
|
|
148
160
|
* Create a new Scell API Client
|
|
@@ -166,12 +178,16 @@ export class ScellApiClient {
|
|
|
166
178
|
|
|
167
179
|
this.invoices = new InvoicesResource(this.http);
|
|
168
180
|
this.signatures = new SignaturesResource(this.http);
|
|
181
|
+
this.tenantCreditNotes = new TenantCreditNotesResource(this.http);
|
|
169
182
|
}
|
|
170
183
|
}
|
|
171
184
|
|
|
172
185
|
// Re-export utilities
|
|
173
186
|
export { ScellAuth, ScellWebhooks, withRetry, createRetryWrapper };
|
|
174
187
|
|
|
188
|
+
// Re-export tenant client
|
|
189
|
+
export { ScellTenantClient };
|
|
190
|
+
|
|
175
191
|
// Re-export types
|
|
176
192
|
export type { ClientConfig } from './client.js';
|
|
177
193
|
export type { RetryOptions } from './utils/retry.js';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Billing Resource
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { HttpClient, RequestOptions } from '../client.js';
|
|
7
|
+
import type { MessageResponse, PaginatedResponse, SingleResponse } from '../types/common.js';
|
|
8
|
+
import type {
|
|
9
|
+
BillingInvoice,
|
|
10
|
+
BillingInvoiceListOptions,
|
|
11
|
+
BillingTopUpConfirmInput,
|
|
12
|
+
BillingTopUpInput,
|
|
13
|
+
BillingTransaction,
|
|
14
|
+
BillingTransactionListOptions,
|
|
15
|
+
BillingUsage,
|
|
16
|
+
BillingUsageOptions,
|
|
17
|
+
} from '../types/billing.js';
|
|
18
|
+
|
|
19
|
+
export class BillingResource {
|
|
20
|
+
constructor(private readonly http: HttpClient) {}
|
|
21
|
+
|
|
22
|
+
async invoices(options: BillingInvoiceListOptions = {}, requestOptions?: RequestOptions): Promise<PaginatedResponse<BillingInvoice>> {
|
|
23
|
+
return this.http.get<PaginatedResponse<BillingInvoice>>('/tenant/billing/invoices', options as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async showInvoice(invoiceId: string, requestOptions?: RequestOptions): Promise<SingleResponse<BillingInvoice>> {
|
|
27
|
+
return this.http.get<SingleResponse<BillingInvoice>>(`/tenant/billing/invoices/${invoiceId}`, undefined, requestOptions);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async downloadInvoice(invoiceId: string, requestOptions?: RequestOptions): Promise<ArrayBuffer> {
|
|
31
|
+
return this.http.getRaw(`/tenant/billing/invoices/${invoiceId}/download`, undefined, requestOptions);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async usage(options: BillingUsageOptions = {}, requestOptions?: RequestOptions): Promise<SingleResponse<BillingUsage>> {
|
|
35
|
+
return this.http.get<SingleResponse<BillingUsage>>('/tenant/billing/usage', options as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async topUp(input: BillingTopUpInput, requestOptions?: RequestOptions): Promise<MessageResponse> {
|
|
39
|
+
return this.http.post<MessageResponse>('/tenant/billing/top-up', input, requestOptions);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async confirmTopUp(input: BillingTopUpConfirmInput, requestOptions?: RequestOptions): Promise<MessageResponse> {
|
|
43
|
+
return this.http.post<MessageResponse>('/tenant/billing/top-up/confirm', input, requestOptions);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async transactions(options: BillingTransactionListOptions = {}, requestOptions?: RequestOptions): Promise<PaginatedResponse<BillingTransaction>> {
|
|
47
|
+
return this.http.get<PaginatedResponse<BillingTransaction>>('/tenant/billing/transactions', options as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fiscal Compliance Resource
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { HttpClient, RequestOptions } from '../client.js';
|
|
7
|
+
import type { MessageResponse, PaginatedResponse, SingleResponse } from '../types/common.js';
|
|
8
|
+
import type {
|
|
9
|
+
FiscalAnchor,
|
|
10
|
+
FiscalAnchorsOptions,
|
|
11
|
+
FiscalAttestation,
|
|
12
|
+
FiscalClosing,
|
|
13
|
+
FiscalClosingsOptions,
|
|
14
|
+
FiscalComplianceData,
|
|
15
|
+
FiscalCreateRuleInput,
|
|
16
|
+
FiscalDailyClosingInput,
|
|
17
|
+
FiscalEntriesOptions,
|
|
18
|
+
FiscalEntry,
|
|
19
|
+
FiscalExportRulesOptions,
|
|
20
|
+
FiscalFecExportOptions,
|
|
21
|
+
FiscalFecExportResult,
|
|
22
|
+
FiscalForensicExportOptions,
|
|
23
|
+
FiscalIntegrityHistoryOptions,
|
|
24
|
+
FiscalIntegrityOptions,
|
|
25
|
+
FiscalIntegrityReport,
|
|
26
|
+
FiscalKillSwitchActivateInput,
|
|
27
|
+
FiscalKillSwitchStatus,
|
|
28
|
+
FiscalReplayRulesInput,
|
|
29
|
+
FiscalRule,
|
|
30
|
+
FiscalRulesOptions,
|
|
31
|
+
FiscalUpdateRuleInput,
|
|
32
|
+
} from '../types/fiscal.js';
|
|
33
|
+
|
|
34
|
+
export class FiscalResource {
|
|
35
|
+
constructor(private readonly http: HttpClient) {}
|
|
36
|
+
|
|
37
|
+
async compliance(requestOptions?: RequestOptions): Promise<SingleResponse<FiscalComplianceData>> {
|
|
38
|
+
return this.http.get<SingleResponse<FiscalComplianceData>>('/tenant/fiscal/compliance', undefined, requestOptions);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async integrity(options: FiscalIntegrityOptions = {}, requestOptions?: RequestOptions): Promise<SingleResponse<FiscalIntegrityReport>> {
|
|
42
|
+
return this.http.get<SingleResponse<FiscalIntegrityReport>>('/tenant/fiscal/integrity', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async integrityHistory(options: FiscalIntegrityHistoryOptions = {}, requestOptions?: RequestOptions): Promise<PaginatedResponse<FiscalIntegrityReport>> {
|
|
46
|
+
return this.http.get<PaginatedResponse<FiscalIntegrityReport>>('/tenant/fiscal/integrity/history', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async integrityForDate(date: string, requestOptions?: RequestOptions): Promise<SingleResponse<FiscalIntegrityReport>> {
|
|
50
|
+
return this.http.get<SingleResponse<FiscalIntegrityReport>>(`/tenant/fiscal/integrity/${date}`, undefined, requestOptions);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async closings(options: FiscalClosingsOptions = {}, requestOptions?: RequestOptions): Promise<PaginatedResponse<FiscalClosing>> {
|
|
54
|
+
return this.http.get<PaginatedResponse<FiscalClosing>>('/tenant/fiscal/closings', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async performDailyClosing(input: FiscalDailyClosingInput = {}, requestOptions?: RequestOptions): Promise<MessageResponse> {
|
|
58
|
+
return this.http.post<MessageResponse>('/tenant/fiscal/closings/daily', input, requestOptions);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async fecExport(options: FiscalFecExportOptions, requestOptions?: RequestOptions): Promise<SingleResponse<FiscalFecExportResult>> {
|
|
62
|
+
return this.http.get<SingleResponse<FiscalFecExportResult>>('/tenant/fiscal/fec', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async fecDownload(options: FiscalFecExportOptions, requestOptions?: RequestOptions): Promise<ArrayBuffer> {
|
|
66
|
+
return this.http.getRaw('/tenant/fiscal/fec', { ...options, download: true } as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async attestation(year: number, requestOptions?: RequestOptions): Promise<SingleResponse<FiscalAttestation>> {
|
|
70
|
+
return this.http.get<SingleResponse<FiscalAttestation>>(`/tenant/fiscal/attestation/${year}`, undefined, requestOptions);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async attestationDownload(year: number, requestOptions?: RequestOptions): Promise<ArrayBuffer> {
|
|
74
|
+
return this.http.getRaw(`/tenant/fiscal/attestation/${year}/download`, undefined, requestOptions);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async entries(options: FiscalEntriesOptions = {}, requestOptions?: RequestOptions): Promise<PaginatedResponse<FiscalEntry>> {
|
|
78
|
+
return this.http.get<PaginatedResponse<FiscalEntry>>('/tenant/fiscal/entries', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async killSwitchStatus(requestOptions?: RequestOptions): Promise<SingleResponse<FiscalKillSwitchStatus>> {
|
|
82
|
+
return this.http.get<SingleResponse<FiscalKillSwitchStatus>>('/tenant/fiscal/kill-switch/status', undefined, requestOptions);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async killSwitchActivate(input: FiscalKillSwitchActivateInput, requestOptions?: RequestOptions): Promise<MessageResponse> {
|
|
86
|
+
return this.http.post<MessageResponse>('/tenant/fiscal/kill-switch/activate', input, requestOptions);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async killSwitchDeactivate(requestOptions?: RequestOptions): Promise<MessageResponse> {
|
|
90
|
+
return this.http.post<MessageResponse>('/tenant/fiscal/kill-switch/deactivate', undefined, requestOptions);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async anchors(options: FiscalAnchorsOptions = {}, requestOptions?: RequestOptions): Promise<PaginatedResponse<FiscalAnchor>> {
|
|
94
|
+
return this.http.get<PaginatedResponse<FiscalAnchor>>('/tenant/fiscal/anchors', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async rules(options: FiscalRulesOptions = {}, requestOptions?: RequestOptions): Promise<PaginatedResponse<FiscalRule>> {
|
|
98
|
+
return this.http.get<PaginatedResponse<FiscalRule>>('/tenant/fiscal/rules', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async ruleDetail(key: string, requestOptions?: RequestOptions): Promise<SingleResponse<FiscalRule>> {
|
|
102
|
+
return this.http.get<SingleResponse<FiscalRule>>(`/tenant/fiscal/rules/${key}`, undefined, requestOptions);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async ruleHistory(key: string, requestOptions?: RequestOptions): Promise<PaginatedResponse<FiscalRule>> {
|
|
106
|
+
return this.http.get<PaginatedResponse<FiscalRule>>(`/tenant/fiscal/rules/${key}/history`, undefined, requestOptions);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async createRule(input: FiscalCreateRuleInput, requestOptions?: RequestOptions): Promise<SingleResponse<FiscalRule>> {
|
|
110
|
+
return this.http.post<SingleResponse<FiscalRule>>('/tenant/fiscal/rules', input, requestOptions);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async updateRule(id: string, input: FiscalUpdateRuleInput, requestOptions?: RequestOptions): Promise<SingleResponse<FiscalRule>> {
|
|
114
|
+
return this.http.post<SingleResponse<FiscalRule>>(`/tenant/fiscal/rules/${id}`, input, requestOptions);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async exportRules(options: FiscalExportRulesOptions, requestOptions?: RequestOptions): Promise<SingleResponse<Record<string, unknown>>> {
|
|
118
|
+
return this.http.get<SingleResponse<Record<string, unknown>>>('/tenant/fiscal/rules/export', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async replayRules(input: FiscalReplayRulesInput, requestOptions?: RequestOptions): Promise<MessageResponse> {
|
|
122
|
+
return this.http.post<MessageResponse>('/tenant/fiscal/rules/replay', input, requestOptions);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async forensicExport(options: FiscalForensicExportOptions, requestOptions?: RequestOptions): Promise<SingleResponse<Record<string, unknown>>> {
|
|
126
|
+
return this.http.get<SingleResponse<Record<string, unknown>>>('/tenant/fiscal/forensic-export', options as unknown as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -11,13 +11,19 @@ import type {
|
|
|
11
11
|
SingleResponse,
|
|
12
12
|
} from '../types/common.js';
|
|
13
13
|
import type {
|
|
14
|
+
AcceptInvoiceInput,
|
|
14
15
|
AuditTrailResponse,
|
|
15
16
|
ConvertInvoiceInput,
|
|
16
17
|
CreateInvoiceInput,
|
|
18
|
+
DisputeInvoiceInput,
|
|
19
|
+
IncomingInvoiceParams,
|
|
17
20
|
Invoice,
|
|
18
21
|
InvoiceDownloadResponse,
|
|
19
22
|
InvoiceDownloadType,
|
|
23
|
+
InvoiceFileFormat,
|
|
20
24
|
InvoiceListOptions,
|
|
25
|
+
MarkPaidInput,
|
|
26
|
+
RejectInvoiceInput,
|
|
21
27
|
} from '../types/invoices.js';
|
|
22
28
|
|
|
23
29
|
/**
|
|
@@ -243,4 +249,215 @@ export class InvoicesResource {
|
|
|
243
249
|
target_format: string;
|
|
244
250
|
}>('/invoices/convert', input, requestOptions);
|
|
245
251
|
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* List incoming invoices (from suppliers)
|
|
255
|
+
*
|
|
256
|
+
* Returns invoices where your company is the buyer.
|
|
257
|
+
*
|
|
258
|
+
* @param params - Filter and pagination options
|
|
259
|
+
* @param requestOptions - Request options
|
|
260
|
+
* @returns Paginated list of incoming invoices
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```typescript
|
|
264
|
+
* // List all incoming invoices
|
|
265
|
+
* const { data, meta } = await client.invoices.incoming({
|
|
266
|
+
* status: 'pending',
|
|
267
|
+
* per_page: 50
|
|
268
|
+
* });
|
|
269
|
+
* console.log(`Found ${meta.total} incoming invoices`);
|
|
270
|
+
*
|
|
271
|
+
* // Filter by seller
|
|
272
|
+
* const fromSupplier = await client.invoices.incoming({
|
|
273
|
+
* seller_siret: '12345678901234'
|
|
274
|
+
* });
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
async incoming(
|
|
278
|
+
params: IncomingInvoiceParams = {},
|
|
279
|
+
requestOptions?: RequestOptions
|
|
280
|
+
): Promise<PaginatedResponse<Invoice>> {
|
|
281
|
+
return this.http.get<PaginatedResponse<Invoice>>(
|
|
282
|
+
'/invoices/incoming',
|
|
283
|
+
params as Record<string, string | number | boolean | undefined>,
|
|
284
|
+
requestOptions
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Accept an incoming invoice
|
|
290
|
+
*
|
|
291
|
+
* Mark an incoming invoice as accepted, optionally specifying a payment date.
|
|
292
|
+
*
|
|
293
|
+
* @param id - Invoice UUID
|
|
294
|
+
* @param data - Optional acceptance data
|
|
295
|
+
* @param requestOptions - Request options
|
|
296
|
+
* @returns Updated invoice
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```typescript
|
|
300
|
+
* // Accept with payment date
|
|
301
|
+
* const { data: invoice } = await client.invoices.accept('invoice-uuid', {
|
|
302
|
+
* payment_date: '2024-02-15',
|
|
303
|
+
* note: 'Approved by accounting'
|
|
304
|
+
* });
|
|
305
|
+
*
|
|
306
|
+
* // Simple acceptance
|
|
307
|
+
* await client.invoices.accept('invoice-uuid');
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
async accept(
|
|
311
|
+
id: string,
|
|
312
|
+
data?: AcceptInvoiceInput,
|
|
313
|
+
requestOptions?: RequestOptions
|
|
314
|
+
): Promise<SingleResponse<Invoice>> {
|
|
315
|
+
return this.http.post<SingleResponse<Invoice>>(
|
|
316
|
+
`/invoices/${id}/accept`,
|
|
317
|
+
data,
|
|
318
|
+
requestOptions
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Reject an incoming invoice
|
|
324
|
+
*
|
|
325
|
+
* Mark an incoming invoice as rejected with a reason.
|
|
326
|
+
*
|
|
327
|
+
* @param id - Invoice UUID
|
|
328
|
+
* @param data - Rejection details
|
|
329
|
+
* @param requestOptions - Request options
|
|
330
|
+
* @returns Updated invoice
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* ```typescript
|
|
334
|
+
* const { data: invoice } = await client.invoices.reject('invoice-uuid', {
|
|
335
|
+
* reason: 'Invoice amount does not match purchase order',
|
|
336
|
+
* reason_code: 'incorrect_amount'
|
|
337
|
+
* });
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
async reject(
|
|
341
|
+
id: string,
|
|
342
|
+
data: RejectInvoiceInput,
|
|
343
|
+
requestOptions?: RequestOptions
|
|
344
|
+
): Promise<SingleResponse<Invoice>> {
|
|
345
|
+
return this.http.post<SingleResponse<Invoice>>(
|
|
346
|
+
`/invoices/${id}/reject`,
|
|
347
|
+
data,
|
|
348
|
+
requestOptions
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Dispute an incoming invoice
|
|
354
|
+
*
|
|
355
|
+
* Open a dispute on an incoming invoice for resolution.
|
|
356
|
+
*
|
|
357
|
+
* @param id - Invoice UUID
|
|
358
|
+
* @param data - Dispute details
|
|
359
|
+
* @param requestOptions - Request options
|
|
360
|
+
* @returns Updated invoice
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```typescript
|
|
364
|
+
* const { data: invoice } = await client.invoices.dispute('invoice-uuid', {
|
|
365
|
+
* reason: 'Billed amount exceeds agreed price',
|
|
366
|
+
* dispute_type: 'amount_dispute',
|
|
367
|
+
* expected_amount: 950.00
|
|
368
|
+
* });
|
|
369
|
+
* ```
|
|
370
|
+
*/
|
|
371
|
+
async dispute(
|
|
372
|
+
id: string,
|
|
373
|
+
data: DisputeInvoiceInput,
|
|
374
|
+
requestOptions?: RequestOptions
|
|
375
|
+
): Promise<SingleResponse<Invoice>> {
|
|
376
|
+
return this.http.post<SingleResponse<Invoice>>(
|
|
377
|
+
`/invoices/${id}/dispute`,
|
|
378
|
+
data,
|
|
379
|
+
requestOptions
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Mark an incoming invoice as paid
|
|
385
|
+
*
|
|
386
|
+
* This is a mandatory step in the French e-invoicing lifecycle for incoming invoices.
|
|
387
|
+
* Once marked as paid, the invoice status changes to 'paid' and payment details are recorded.
|
|
388
|
+
*
|
|
389
|
+
* @param id - Invoice UUID
|
|
390
|
+
* @param data - Optional payment details (reference, date, note)
|
|
391
|
+
* @param requestOptions - Request options
|
|
392
|
+
* @returns Updated invoice with payment information
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```typescript
|
|
396
|
+
* // Mark as paid with payment details
|
|
397
|
+
* const { data: invoice } = await client.invoices.markPaid('invoice-uuid', {
|
|
398
|
+
* payment_reference: 'VIR-2026-0124',
|
|
399
|
+
* paid_at: '2026-01-24T10:30:00Z',
|
|
400
|
+
* note: 'Payment received via bank transfer'
|
|
401
|
+
* });
|
|
402
|
+
*
|
|
403
|
+
* // Simple mark as paid (uses current date/time)
|
|
404
|
+
* await client.invoices.markPaid('invoice-uuid');
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
async markPaid(
|
|
408
|
+
id: string,
|
|
409
|
+
data?: MarkPaidInput,
|
|
410
|
+
requestOptions?: RequestOptions
|
|
411
|
+
): Promise<SingleResponse<Invoice>> {
|
|
412
|
+
return this.http.post<SingleResponse<Invoice>>(
|
|
413
|
+
`/invoices/${id}/mark-paid`,
|
|
414
|
+
data,
|
|
415
|
+
requestOptions
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Download invoice source file as binary content
|
|
421
|
+
*
|
|
422
|
+
* Downloads the original invoice file (PDF with embedded XML for Factur-X,
|
|
423
|
+
* or standalone XML for UBL/CII formats).
|
|
424
|
+
*
|
|
425
|
+
* @param id - Invoice UUID
|
|
426
|
+
* @param format - File format to download: 'pdf' (default) or 'xml'
|
|
427
|
+
* @param requestOptions - Request options
|
|
428
|
+
* @returns ArrayBuffer containing the file content
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```typescript
|
|
432
|
+
* // Download invoice as PDF (Factur-X)
|
|
433
|
+
* const pdfBuffer = await client.invoices.downloadFile('invoice-uuid');
|
|
434
|
+
*
|
|
435
|
+
* // In Node.js, save to file:
|
|
436
|
+
* import { writeFileSync } from 'fs';
|
|
437
|
+
* writeFileSync('invoice.pdf', Buffer.from(pdfBuffer));
|
|
438
|
+
*
|
|
439
|
+
* // Download XML version (UBL/CII)
|
|
440
|
+
* const xmlBuffer = await client.invoices.downloadFile('invoice-uuid', 'xml');
|
|
441
|
+
* writeFileSync('invoice.xml', Buffer.from(xmlBuffer));
|
|
442
|
+
*
|
|
443
|
+
* // In browser, trigger download:
|
|
444
|
+
* const blob = new Blob([pdfBuffer], { type: 'application/pdf' });
|
|
445
|
+
* const url = URL.createObjectURL(blob);
|
|
446
|
+
* const a = document.createElement('a');
|
|
447
|
+
* a.href = url;
|
|
448
|
+
* a.download = 'invoice.pdf';
|
|
449
|
+
* a.click();
|
|
450
|
+
* ```
|
|
451
|
+
*/
|
|
452
|
+
async downloadFile(
|
|
453
|
+
id: string,
|
|
454
|
+
format: InvoiceFileFormat = 'pdf',
|
|
455
|
+
requestOptions?: RequestOptions
|
|
456
|
+
): Promise<ArrayBuffer> {
|
|
457
|
+
return this.http.getRaw(
|
|
458
|
+
`/invoices/${id}/download`,
|
|
459
|
+
{ format },
|
|
460
|
+
requestOptions
|
|
461
|
+
);
|
|
462
|
+
}
|
|
246
463
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stats Resource
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { HttpClient, RequestOptions } from '../client.js';
|
|
7
|
+
import type { SingleResponse } from '../types/common.js';
|
|
8
|
+
import type {
|
|
9
|
+
StatsMonthly,
|
|
10
|
+
StatsMonthlyOptions,
|
|
11
|
+
StatsOverview,
|
|
12
|
+
StatsOverviewOptions,
|
|
13
|
+
} from '../types/stats.js';
|
|
14
|
+
|
|
15
|
+
export class StatsResource {
|
|
16
|
+
constructor(private readonly http: HttpClient) {}
|
|
17
|
+
|
|
18
|
+
async overview(options: StatsOverviewOptions = {}, requestOptions?: RequestOptions): Promise<SingleResponse<StatsOverview>> {
|
|
19
|
+
return this.http.get<SingleResponse<StatsOverview>>('/tenant/stats/overview', options as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async monthly(options: StatsMonthlyOptions = {}, requestOptions?: RequestOptions): Promise<SingleResponse<StatsMonthly[]>> {
|
|
23
|
+
return this.http.get<SingleResponse<StatsMonthly[]>>('/tenant/stats/monthly', options as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async subTenantOverview(subTenantId: string, options: StatsOverviewOptions = {}, requestOptions?: RequestOptions): Promise<SingleResponse<StatsOverview>> {
|
|
27
|
+
return this.http.get<SingleResponse<StatsOverview>>(`/tenant/sub-tenants/${subTenantId}/stats/overview`, options as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sub-Tenants Resource
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { HttpClient, RequestOptions } from '../client.js';
|
|
7
|
+
import type { MessageResponse, PaginatedResponse, SingleResponse } from '../types/common.js';
|
|
8
|
+
import type {
|
|
9
|
+
CreateSubTenantInput,
|
|
10
|
+
SubTenant,
|
|
11
|
+
SubTenantListOptions,
|
|
12
|
+
UpdateSubTenantInput,
|
|
13
|
+
} from '../types/sub-tenants.js';
|
|
14
|
+
|
|
15
|
+
export class SubTenantsResource {
|
|
16
|
+
constructor(private readonly http: HttpClient) {}
|
|
17
|
+
|
|
18
|
+
async list(options: SubTenantListOptions = {}, requestOptions?: RequestOptions): Promise<PaginatedResponse<SubTenant>> {
|
|
19
|
+
return this.http.get<PaginatedResponse<SubTenant>>('/tenant/sub-tenants', options as Record<string, string | number | boolean | undefined>, requestOptions);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async create(input: CreateSubTenantInput, requestOptions?: RequestOptions): Promise<SingleResponse<SubTenant>> {
|
|
23
|
+
return this.http.post<SingleResponse<SubTenant>>('/tenant/sub-tenants', input, requestOptions);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async get(id: string, requestOptions?: RequestOptions): Promise<SingleResponse<SubTenant>> {
|
|
27
|
+
return this.http.get<SingleResponse<SubTenant>>(`/tenant/sub-tenants/${id}`, undefined, requestOptions);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async update(id: string, input: UpdateSubTenantInput, requestOptions?: RequestOptions): Promise<SingleResponse<SubTenant>> {
|
|
31
|
+
return this.http.patch<SingleResponse<SubTenant>>(`/tenant/sub-tenants/${id}`, input, requestOptions);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async delete(id: string, requestOptions?: RequestOptions): Promise<MessageResponse> {
|
|
35
|
+
return this.http.delete<MessageResponse>(`/tenant/sub-tenants/${id}`, requestOptions);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async findByExternalId(externalId: string, requestOptions?: RequestOptions): Promise<SingleResponse<SubTenant>> {
|
|
39
|
+
return this.http.get<SingleResponse<SubTenant>>(`/tenant/sub-tenants/by-external-id/${externalId}`, undefined, requestOptions);
|
|
40
|
+
}
|
|
41
|
+
}
|