@scell/sdk 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scell/sdk",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Official TypeScript SDK for Scell.io - Electronic invoicing (Factur-X) and signatures (eIDAS) API",
5
5
  "author": "Scell.io <contact@scell.io>",
6
6
  "license": "MIT",
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
  }
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
+ }
@@ -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
+ }
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Tenant Credit Notes Resource
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+
7
+ import type { HttpClient, RequestOptions } from '../client.js';
8
+ import type {
9
+ MessageResponse,
10
+ PaginatedResponse,
11
+ SingleResponse,
12
+ } from '../types/common.js';
13
+ import type {
14
+ CreateTenantCreditNoteInput,
15
+ RemainingCreditable,
16
+ TenantCreditNote,
17
+ TenantCreditNoteListOptions,
18
+ UpdateTenantCreditNoteInput,
19
+ } from '../types/tenant-credit-notes.js';
20
+
21
+ /**
22
+ * Tenant Credit Notes API resource
23
+ *
24
+ * Manage credit notes for sub-tenant invoices.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // List credit notes for a sub-tenant
29
+ * const { data, meta } = await client.tenantCreditNotes.list('sub-tenant-uuid', {
30
+ * status: 'sent'
31
+ * });
32
+ *
33
+ * // Create a credit note
34
+ * const creditNote = await client.tenantCreditNotes.create('sub-tenant-uuid', {
35
+ * invoice_id: 'invoice-uuid',
36
+ * reason: 'Product returned',
37
+ * type: 'partial',
38
+ * items: [{ invoice_line_id: 'line-uuid', quantity: 1 }]
39
+ * });
40
+ * ```
41
+ */
42
+ export class TenantCreditNotesResource {
43
+ constructor(private readonly http: HttpClient) {}
44
+
45
+ /**
46
+ * List credit notes for a sub-tenant
47
+ *
48
+ * @param subTenantId - Sub-tenant UUID
49
+ * @param options - Filter and pagination options
50
+ * @param requestOptions - Request options
51
+ * @returns Paginated list of credit notes
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const { data, meta } = await client.tenantCreditNotes.list('sub-tenant-uuid', {
56
+ * status: 'sent',
57
+ * date_from: '2024-01-01',
58
+ * per_page: 50
59
+ * });
60
+ * console.log(`Found ${meta.total} credit notes`);
61
+ * ```
62
+ */
63
+ async list(
64
+ subTenantId: string,
65
+ options: TenantCreditNoteListOptions = {},
66
+ requestOptions?: RequestOptions
67
+ ): Promise<PaginatedResponse<TenantCreditNote>> {
68
+ return this.http.get<PaginatedResponse<TenantCreditNote>>(
69
+ `/tenant/sub-tenants/${subTenantId}/credit-notes`,
70
+ options as Record<string, string | number | boolean | undefined>,
71
+ requestOptions
72
+ );
73
+ }
74
+
75
+ /**
76
+ * Create a new credit note for a sub-tenant invoice
77
+ *
78
+ * @param subTenantId - Sub-tenant UUID
79
+ * @param input - Credit note creation data
80
+ * @param requestOptions - Request options
81
+ * @returns Created credit note
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * // Create a partial credit note
86
+ * const { data: creditNote } = await client.tenantCreditNotes.create(
87
+ * 'sub-tenant-uuid',
88
+ * {
89
+ * invoice_id: 'invoice-uuid',
90
+ * reason: 'Product returned - damaged item',
91
+ * type: 'partial',
92
+ * items: [
93
+ * { invoice_line_id: 'line-uuid-1', quantity: 2 }
94
+ * ]
95
+ * }
96
+ * );
97
+ *
98
+ * // Create a total credit note
99
+ * const { data: totalCreditNote } = await client.tenantCreditNotes.create(
100
+ * 'sub-tenant-uuid',
101
+ * {
102
+ * invoice_id: 'invoice-uuid',
103
+ * reason: 'Order cancelled',
104
+ * type: 'total'
105
+ * }
106
+ * );
107
+ * ```
108
+ */
109
+ async create(
110
+ subTenantId: string,
111
+ input: CreateTenantCreditNoteInput,
112
+ requestOptions?: RequestOptions
113
+ ): Promise<SingleResponse<TenantCreditNote>> {
114
+ return this.http.post<SingleResponse<TenantCreditNote>>(
115
+ `/tenant/sub-tenants/${subTenantId}/credit-notes`,
116
+ input,
117
+ requestOptions
118
+ );
119
+ }
120
+
121
+ /**
122
+ * Get a specific credit note by ID
123
+ *
124
+ * @param creditNoteId - Credit note UUID
125
+ * @param requestOptions - Request options
126
+ * @returns Credit note details
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * const { data: creditNote } = await client.tenantCreditNotes.get('credit-note-uuid');
131
+ * console.log('Credit note number:', creditNote.credit_note_number);
132
+ * console.log('Total:', creditNote.total, creditNote.currency);
133
+ * ```
134
+ */
135
+ async get(
136
+ creditNoteId: string,
137
+ requestOptions?: RequestOptions
138
+ ): Promise<SingleResponse<TenantCreditNote>> {
139
+ return this.http.get<SingleResponse<TenantCreditNote>>(
140
+ `/tenant/credit-notes/${creditNoteId}`,
141
+ undefined,
142
+ requestOptions
143
+ );
144
+ }
145
+
146
+ /**
147
+ * Update a credit note
148
+ *
149
+ * Only credit notes in 'draft' status can be updated.
150
+ *
151
+ * @param creditNoteId - Credit note UUID
152
+ * @param input - Update data
153
+ * @param requestOptions - Request options
154
+ * @returns Updated credit note
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * const { data: creditNote } = await client.tenantCreditNotes.update(
159
+ * 'credit-note-uuid',
160
+ * {
161
+ * reason: 'Updated reason: Customer complaint resolved',
162
+ * items: [
163
+ * { invoice_line_id: 'line-uuid', quantity: 3 }
164
+ * ]
165
+ * }
166
+ * );
167
+ * console.log('Credit note updated:', creditNote.reason);
168
+ * ```
169
+ */
170
+ async update(
171
+ creditNoteId: string,
172
+ input: UpdateTenantCreditNoteInput,
173
+ requestOptions?: RequestOptions
174
+ ): Promise<SingleResponse<TenantCreditNote>> {
175
+ return this.http.patch<SingleResponse<TenantCreditNote>>(
176
+ `/tenant/credit-notes/${creditNoteId}`,
177
+ input,
178
+ requestOptions
179
+ );
180
+ }
181
+
182
+ /**
183
+ * Send a credit note
184
+ *
185
+ * Changes the status from 'draft' to 'sent'.
186
+ *
187
+ * @param creditNoteId - Credit note UUID
188
+ * @param requestOptions - Request options
189
+ * @returns Updated credit note
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * const { data: sentCreditNote } = await client.tenantCreditNotes.send('credit-note-uuid');
194
+ * console.log('Status:', sentCreditNote.status); // 'sent'
195
+ * ```
196
+ */
197
+ async send(
198
+ creditNoteId: string,
199
+ requestOptions?: RequestOptions
200
+ ): Promise<SingleResponse<TenantCreditNote>> {
201
+ return this.http.post<SingleResponse<TenantCreditNote>>(
202
+ `/tenant/credit-notes/${creditNoteId}/send`,
203
+ undefined,
204
+ requestOptions
205
+ );
206
+ }
207
+
208
+ /**
209
+ * Delete a credit note (draft only)
210
+ *
211
+ * Only credit notes with status 'draft' can be deleted.
212
+ *
213
+ * @param creditNoteId - Credit note UUID
214
+ * @param requestOptions - Request options
215
+ *
216
+ * @example
217
+ * ```typescript
218
+ * await client.tenantCreditNotes.delete('credit-note-uuid');
219
+ * ```
220
+ */
221
+ async delete(
222
+ creditNoteId: string,
223
+ requestOptions?: RequestOptions
224
+ ): Promise<MessageResponse> {
225
+ return this.http.delete<MessageResponse>(
226
+ `/tenant/credit-notes/${creditNoteId}`,
227
+ requestOptions
228
+ );
229
+ }
230
+
231
+ /**
232
+ * Download credit note as PDF
233
+ *
234
+ * @param creditNoteId - Credit note UUID
235
+ * @param requestOptions - Request options
236
+ * @returns ArrayBuffer containing the PDF file
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * // Download credit note PDF
241
+ * const pdfBuffer = await client.tenantCreditNotes.download('credit-note-uuid');
242
+ *
243
+ * // In Node.js, save to file:
244
+ * import { writeFileSync } from 'fs';
245
+ * writeFileSync('credit-note.pdf', Buffer.from(pdfBuffer));
246
+ *
247
+ * // In browser, trigger download:
248
+ * const blob = new Blob([pdfBuffer], { type: 'application/pdf' });
249
+ * const url = URL.createObjectURL(blob);
250
+ * const a = document.createElement('a');
251
+ * a.href = url;
252
+ * a.download = 'credit-note.pdf';
253
+ * a.click();
254
+ * ```
255
+ */
256
+ async download(
257
+ creditNoteId: string,
258
+ requestOptions?: RequestOptions
259
+ ): Promise<ArrayBuffer> {
260
+ return this.http.getRaw(
261
+ `/tenant/credit-notes/${creditNoteId}/download`,
262
+ undefined,
263
+ requestOptions
264
+ );
265
+ }
266
+
267
+ /**
268
+ * Get remaining creditable amount for an invoice
269
+ *
270
+ * Returns information about how much can still be credited for an invoice,
271
+ * including per-line breakdown.
272
+ *
273
+ * @param invoiceId - Invoice UUID
274
+ * @param requestOptions - Request options
275
+ * @returns Remaining creditable information
276
+ *
277
+ * @example
278
+ * ```typescript
279
+ * const remaining = await client.tenantCreditNotes.remainingCreditable('invoice-uuid');
280
+ *
281
+ * console.log('Invoice total:', remaining.invoice_total);
282
+ * console.log('Already credited:', remaining.credited_total);
283
+ * console.log('Remaining to credit:', remaining.remaining_total);
284
+ *
285
+ * // Check remaining quantity per line
286
+ * remaining.lines.forEach(line => {
287
+ * console.log(`${line.description}: ${line.remaining_quantity} remaining`);
288
+ * });
289
+ * ```
290
+ */
291
+ async remainingCreditable(
292
+ invoiceId: string,
293
+ requestOptions?: RequestOptions
294
+ ): Promise<RemainingCreditable> {
295
+ return this.http.get<RemainingCreditable>(
296
+ `/tenant/invoices/${invoiceId}/remaining-creditable`,
297
+ undefined,
298
+ requestOptions
299
+ );
300
+ }
301
+ }