tiime-sdk 2.1.1 → 2.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/index.d.ts +47 -27
- package/dist/index.js +2 -811
- package/package.json +1 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { $Fetch } from 'ofetch';
|
|
2
|
-
|
|
3
1
|
interface AuthTokens {
|
|
4
2
|
access_token: string;
|
|
5
3
|
expires_at: number;
|
|
@@ -153,10 +151,16 @@ interface BankTransaction {
|
|
|
153
151
|
status: string;
|
|
154
152
|
status_code: string;
|
|
155
153
|
comment: string | null;
|
|
156
|
-
tags:
|
|
154
|
+
tags: Tag[];
|
|
157
155
|
short_bank_name: string;
|
|
158
|
-
beneficiary:
|
|
159
|
-
|
|
156
|
+
beneficiary: {
|
|
157
|
+
id: number;
|
|
158
|
+
name: string;
|
|
159
|
+
} | null;
|
|
160
|
+
merchant: {
|
|
161
|
+
id: number;
|
|
162
|
+
name: string;
|
|
163
|
+
} | null;
|
|
160
164
|
transfer_label: string | null;
|
|
161
165
|
imputations: Imputation[];
|
|
162
166
|
count_documents: number;
|
|
@@ -165,7 +169,9 @@ interface BankTransaction {
|
|
|
165
169
|
interface BankTransactionsResponse {
|
|
166
170
|
metadata: {
|
|
167
171
|
has_multiple_cardholder: boolean;
|
|
168
|
-
accountant_detail_request_data:
|
|
172
|
+
accountant_detail_request_data: {
|
|
173
|
+
id: number;
|
|
174
|
+
}[];
|
|
169
175
|
total_amount: number;
|
|
170
176
|
};
|
|
171
177
|
transactions: BankTransaction[];
|
|
@@ -218,7 +224,9 @@ interface InvoiceCreateParams {
|
|
|
218
224
|
title?: string | null;
|
|
219
225
|
title_enabled?: boolean;
|
|
220
226
|
lines: InvoiceLine[];
|
|
221
|
-
text_lines?:
|
|
227
|
+
text_lines?: {
|
|
228
|
+
text: string;
|
|
229
|
+
}[];
|
|
222
230
|
status?: "draft" | "saved";
|
|
223
231
|
template?: string;
|
|
224
232
|
free_field?: string;
|
|
@@ -246,7 +254,7 @@ interface Invoice {
|
|
|
246
254
|
lines: InvoiceLine[];
|
|
247
255
|
type: string;
|
|
248
256
|
color: string;
|
|
249
|
-
tags:
|
|
257
|
+
tags: Tag[];
|
|
250
258
|
totals_per_vat_type: Record<string, {
|
|
251
259
|
total_excluding_taxes: number;
|
|
252
260
|
vat_amount: number;
|
|
@@ -414,7 +422,11 @@ interface MatchableDocument {
|
|
|
414
422
|
mime_type: string;
|
|
415
423
|
name: string;
|
|
416
424
|
type: string;
|
|
417
|
-
metadata:
|
|
425
|
+
metadata: {
|
|
426
|
+
date?: string | null;
|
|
427
|
+
amount?: number | null;
|
|
428
|
+
supplier_name?: string | null;
|
|
429
|
+
}[];
|
|
418
430
|
created_at: string;
|
|
419
431
|
tags: {
|
|
420
432
|
id: number;
|
|
@@ -460,10 +472,18 @@ declare class TokenManager {
|
|
|
460
472
|
private saveToDisk;
|
|
461
473
|
}
|
|
462
474
|
|
|
475
|
+
interface FetchOptions {
|
|
476
|
+
method?: string;
|
|
477
|
+
headers?: Record<string, string>;
|
|
478
|
+
body?: unknown;
|
|
479
|
+
query?: Record<string, unknown> | object;
|
|
480
|
+
}
|
|
481
|
+
type FetchFn = <T = unknown>(url: string, options?: FetchOptions) => Promise<T>;
|
|
482
|
+
|
|
463
483
|
declare class BankAccountsResource {
|
|
464
484
|
private fetch;
|
|
465
485
|
private companyId;
|
|
466
|
-
constructor(fetch:
|
|
486
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
467
487
|
list(enabled?: boolean): Promise<BankAccount[]>;
|
|
468
488
|
get(bankAccountId: number): Promise<BankAccount>;
|
|
469
489
|
balance(): Promise<{
|
|
@@ -488,7 +508,7 @@ interface BankTransactionsListParams {
|
|
|
488
508
|
declare class BankTransactionsResource {
|
|
489
509
|
private fetch;
|
|
490
510
|
private companyId;
|
|
491
|
-
constructor(fetch:
|
|
511
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
492
512
|
list(params?: BankTransactionsListParams): Promise<BankTransactionsResponse>;
|
|
493
513
|
listAll(params?: Omit<BankTransactionsListParams, "page">): Promise<BankTransaction[]>;
|
|
494
514
|
unimputed(): Promise<BankTransaction[]>;
|
|
@@ -518,7 +538,7 @@ interface ClientCreateParams {
|
|
|
518
538
|
declare class ClientsResource {
|
|
519
539
|
private fetch;
|
|
520
540
|
private companyId;
|
|
521
|
-
constructor(fetch:
|
|
541
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
522
542
|
list(params?: ClientsListParams): Promise<Client[]>;
|
|
523
543
|
get(clientId: number): Promise<Client>;
|
|
524
544
|
create(params: ClientCreateParams): Promise<Client>;
|
|
@@ -528,13 +548,13 @@ declare class ClientsResource {
|
|
|
528
548
|
declare class CompanyResource {
|
|
529
549
|
private fetch;
|
|
530
550
|
private companyId;
|
|
531
|
-
constructor(fetch:
|
|
551
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
532
552
|
get(): Promise<Company>;
|
|
533
|
-
users(): Promise<
|
|
534
|
-
appConfig(): Promise<
|
|
553
|
+
users(): Promise<unknown>;
|
|
554
|
+
appConfig(): Promise<unknown>;
|
|
535
555
|
accountingPeriod(rangeYear?: number): Promise<AccountingPeriod>;
|
|
536
|
-
tiles(keys: string[]): Promise<
|
|
537
|
-
dashboardBlocks(displayGroup?: string): Promise<
|
|
556
|
+
tiles(keys: string[]): Promise<unknown>;
|
|
557
|
+
dashboardBlocks(displayGroup?: string): Promise<unknown>;
|
|
538
558
|
}
|
|
539
559
|
|
|
540
560
|
interface DocumentsListParams {
|
|
@@ -548,10 +568,10 @@ interface DocumentsListParams {
|
|
|
548
568
|
declare class DocumentsResource {
|
|
549
569
|
private fetch;
|
|
550
570
|
private companyId;
|
|
551
|
-
constructor(fetch:
|
|
571
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
552
572
|
list(params?: DocumentsListParams): Promise<Document[]>;
|
|
553
573
|
categories(): Promise<DocumentCategory[]>;
|
|
554
|
-
preview(documentId: number): Promise<
|
|
574
|
+
preview(documentId: number): Promise<unknown>;
|
|
555
575
|
upload(file: Uint8Array, filename: string, type?: string): Promise<Document>;
|
|
556
576
|
searchMatchable(query: string): Promise<MatchableDocument[]>;
|
|
557
577
|
download(documentId: number): Promise<ArrayBuffer>;
|
|
@@ -560,7 +580,7 @@ declare class DocumentsResource {
|
|
|
560
580
|
declare class ExpenseReportsResource {
|
|
561
581
|
private fetch;
|
|
562
582
|
private companyId;
|
|
563
|
-
constructor(fetch:
|
|
583
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
564
584
|
list(sorts?: string): Promise<ExpenseReport[]>;
|
|
565
585
|
get(expenseReportId: number): Promise<ExpenseReport>;
|
|
566
586
|
create(params: ExpenseReportCreateParams): Promise<ExpenseReport>;
|
|
@@ -575,7 +595,7 @@ interface InvoicesListParams {
|
|
|
575
595
|
declare class InvoicesResource {
|
|
576
596
|
private fetch;
|
|
577
597
|
private companyId;
|
|
578
|
-
constructor(fetch:
|
|
598
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
579
599
|
list(params?: InvoicesListParams): Promise<Invoice[]>;
|
|
580
600
|
listAll(params?: {
|
|
581
601
|
sorts?: string;
|
|
@@ -597,7 +617,7 @@ declare class InvoicesResource {
|
|
|
597
617
|
declare class LabelsResource {
|
|
598
618
|
private fetch;
|
|
599
619
|
private companyId;
|
|
600
|
-
constructor(fetch:
|
|
620
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
601
621
|
list(): Promise<Label[]>;
|
|
602
622
|
standard(): Promise<Label[]>;
|
|
603
623
|
tags(): Promise<Tag[]>;
|
|
@@ -606,7 +626,7 @@ declare class LabelsResource {
|
|
|
606
626
|
declare class QuotationsResource {
|
|
607
627
|
private fetch;
|
|
608
628
|
private companyId;
|
|
609
|
-
constructor(fetch:
|
|
629
|
+
constructor(fetch: FetchFn, companyId: number);
|
|
610
630
|
list(expand?: string): Promise<Quotation[]>;
|
|
611
631
|
get(quotationId: number): Promise<Quotation>;
|
|
612
632
|
create(params: QuotationCreateParams): Promise<Quotation>;
|
|
@@ -616,14 +636,14 @@ declare class QuotationsResource {
|
|
|
616
636
|
|
|
617
637
|
declare class UsersResource {
|
|
618
638
|
private fetch;
|
|
619
|
-
constructor(fetch:
|
|
639
|
+
constructor(fetch: FetchFn);
|
|
620
640
|
me(): Promise<User>;
|
|
621
|
-
legalInformations(): Promise<
|
|
622
|
-
settings(companyId: number): Promise<
|
|
641
|
+
legalInformations(): Promise<unknown>;
|
|
642
|
+
settings(companyId: number): Promise<unknown>;
|
|
623
643
|
}
|
|
624
644
|
|
|
625
645
|
declare class TiimeClient {
|
|
626
|
-
readonly fetch:
|
|
646
|
+
readonly fetch: FetchFn;
|
|
627
647
|
readonly tokenManager: TokenManager;
|
|
628
648
|
readonly companyId: number;
|
|
629
649
|
constructor(options?: TiimeClientOptions & {
|
package/dist/index.js
CHANGED
|
@@ -1,811 +1,2 @@
|
|
|
1
|
-
// src/auth.ts
|
|
2
|
-
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
-
import { homedir } from "os";
|
|
5
|
-
import { join } from "path";
|
|
6
|
-
import { ofetch } from "ofetch";
|
|
7
|
-
var AUTH0_DOMAIN = "auth0.tiime.fr";
|
|
8
|
-
var AUTH0_CLIENT_ID = "iEbsbe3o66gcTBfGRa012kj1Rb6vjAND";
|
|
9
|
-
var AUTH0_AUDIENCE = "https://chronos/";
|
|
10
|
-
var CONFIG_DIR = join(homedir(), ".config", "tiime");
|
|
11
|
-
var AUTH_FILE = join(CONFIG_DIR, "auth.json");
|
|
12
|
-
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
13
|
-
var KEYCHAIN_ACCOUNT = "tiime-cli";
|
|
14
|
-
var KEYCHAIN_SERVICE = "tiime-credentials";
|
|
15
|
-
var saveCredentialsToKeychain = (email, password) => {
|
|
16
|
-
try {
|
|
17
|
-
const payload = JSON.stringify({ email, password });
|
|
18
|
-
execSync(
|
|
19
|
-
`security add-generic-password -a "${KEYCHAIN_ACCOUNT}" -s "${KEYCHAIN_SERVICE}" -w '${payload.replace(/'/g, "'\\''")}' -U`,
|
|
20
|
-
{ stdio: "ignore" }
|
|
21
|
-
);
|
|
22
|
-
return true;
|
|
23
|
-
} catch {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var loadCredentialsFromKeychain = () => {
|
|
28
|
-
try {
|
|
29
|
-
const raw = execSync(
|
|
30
|
-
`security find-generic-password -a "${KEYCHAIN_ACCOUNT}" -s "${KEYCHAIN_SERVICE}" -w`,
|
|
31
|
-
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
32
|
-
).trim();
|
|
33
|
-
const data = JSON.parse(raw);
|
|
34
|
-
if (typeof data === "object" && data !== null && "email" in data && "password" in data && typeof data.email === "string" && typeof data.password === "string") {
|
|
35
|
-
return data;
|
|
36
|
-
}
|
|
37
|
-
return null;
|
|
38
|
-
} catch {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
var saveCredentialsToFile = (email, password) => {
|
|
43
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
44
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
45
|
-
}
|
|
46
|
-
const filePath = join(CONFIG_DIR, "credentials.json");
|
|
47
|
-
writeFileSync(filePath, JSON.stringify({ email, password }, null, 2), {
|
|
48
|
-
mode: 384
|
|
49
|
-
});
|
|
50
|
-
};
|
|
51
|
-
var loadCredentialsFromFile = () => {
|
|
52
|
-
try {
|
|
53
|
-
const filePath = join(CONFIG_DIR, "credentials.json");
|
|
54
|
-
if (existsSync(filePath)) {
|
|
55
|
-
const data = JSON.parse(readFileSync(filePath, "utf-8"));
|
|
56
|
-
if (typeof data === "object" && data !== null && "email" in data && "password" in data && typeof data.email === "string" && typeof data.password === "string") {
|
|
57
|
-
return data;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
} catch {
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
};
|
|
64
|
-
var saveCredentials = (email, password) => {
|
|
65
|
-
if (!saveCredentialsToKeychain(email, password)) {
|
|
66
|
-
saveCredentialsToFile(email, password);
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
var loadCredentials = () => {
|
|
70
|
-
return loadCredentialsFromKeychain() ?? loadCredentialsFromFile();
|
|
71
|
-
};
|
|
72
|
-
var resolveCompanyId = (explicit) => {
|
|
73
|
-
if (explicit) return explicit;
|
|
74
|
-
const envId = process.env.TIIME_COMPANY_ID;
|
|
75
|
-
if (envId) {
|
|
76
|
-
const parsed = Number.parseInt(envId, 10);
|
|
77
|
-
if (!Number.isNaN(parsed)) return parsed;
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
if (existsSync(CONFIG_FILE)) {
|
|
81
|
-
const config = JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
82
|
-
if (config.companyId) return config.companyId;
|
|
83
|
-
}
|
|
84
|
-
} catch {
|
|
85
|
-
}
|
|
86
|
-
throw new Error(
|
|
87
|
-
"No company ID configured. Set TIIME_COMPANY_ID env var, pass companyId option, or run `tiime company use --id <ID>`."
|
|
88
|
-
);
|
|
89
|
-
};
|
|
90
|
-
var TokenManager = class {
|
|
91
|
-
tokens = null;
|
|
92
|
-
credentials = null;
|
|
93
|
-
persist;
|
|
94
|
-
/**
|
|
95
|
-
* @param options.tokens - Use these tokens directly (no disk I/O)
|
|
96
|
-
* @param options.email - Login with these credentials
|
|
97
|
-
* @param options.password - Login with these credentials
|
|
98
|
-
* @param options.persist - Save tokens/credentials to disk (default: true when no explicit auth)
|
|
99
|
-
*/
|
|
100
|
-
constructor(options = {}) {
|
|
101
|
-
const hasExplicitAuth = options.tokens || options.email && options.password;
|
|
102
|
-
this.persist = options.persist ?? !hasExplicitAuth;
|
|
103
|
-
if (options.tokens) {
|
|
104
|
-
this.tokens = options.tokens;
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (options.email && options.password) {
|
|
108
|
-
this.credentials = { email: options.email, password: options.password };
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
const envToken = process.env.TIIME_ACCESS_TOKEN;
|
|
112
|
-
if (envToken) {
|
|
113
|
-
this.tokens = {
|
|
114
|
-
access_token: envToken,
|
|
115
|
-
// No expiry info from env — assume valid, never auto-refresh
|
|
116
|
-
expires_at: Number.MAX_SAFE_INTEGER
|
|
117
|
-
};
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const envEmail = process.env.TIIME_EMAIL;
|
|
121
|
-
const envPassword = process.env.TIIME_PASSWORD;
|
|
122
|
-
if (envEmail && envPassword) {
|
|
123
|
-
this.credentials = { email: envEmail, password: envPassword };
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
this.loadFromDisk();
|
|
127
|
-
}
|
|
128
|
-
async login(email, password) {
|
|
129
|
-
const response = await ofetch(`https://${AUTH0_DOMAIN}/oauth/token`, {
|
|
130
|
-
method: "POST",
|
|
131
|
-
body: {
|
|
132
|
-
grant_type: "password",
|
|
133
|
-
client_id: AUTH0_CLIENT_ID,
|
|
134
|
-
audience: AUTH0_AUDIENCE,
|
|
135
|
-
scope: "openid email",
|
|
136
|
-
username: email,
|
|
137
|
-
password
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
this.tokens = {
|
|
141
|
-
access_token: response.access_token,
|
|
142
|
-
expires_at: Date.now() + response.expires_in * 1e3
|
|
143
|
-
};
|
|
144
|
-
if (this.persist) {
|
|
145
|
-
this.saveToDisk();
|
|
146
|
-
saveCredentials(email, password);
|
|
147
|
-
}
|
|
148
|
-
return this.tokens;
|
|
149
|
-
}
|
|
150
|
-
async getValidToken() {
|
|
151
|
-
if (!this.tokens || this.isExpired()) {
|
|
152
|
-
const creds = this.credentials ?? loadCredentials();
|
|
153
|
-
if (creds) {
|
|
154
|
-
const tokens = await this.login(creds.email, creds.password);
|
|
155
|
-
return tokens.access_token;
|
|
156
|
-
}
|
|
157
|
-
throw new Error(
|
|
158
|
-
this.tokens ? "Token expired. Provide credentials via options, TIIME_EMAIL/TIIME_PASSWORD env vars, or run `tiime auth login`." : "Not authenticated. Provide credentials via options, TIIME_EMAIL/TIIME_PASSWORD env vars, or run `tiime auth login`."
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
return this.tokens.access_token;
|
|
162
|
-
}
|
|
163
|
-
isAuthenticated() {
|
|
164
|
-
return this.tokens !== null && !this.isExpired();
|
|
165
|
-
}
|
|
166
|
-
logout() {
|
|
167
|
-
this.tokens = null;
|
|
168
|
-
if (existsSync(AUTH_FILE)) {
|
|
169
|
-
writeFileSync(AUTH_FILE, "{}");
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
getTokenInfo() {
|
|
173
|
-
if (!this.tokens) {
|
|
174
|
-
return { email: null, expiresAt: null };
|
|
175
|
-
}
|
|
176
|
-
try {
|
|
177
|
-
const payload = JSON.parse(
|
|
178
|
-
Buffer.from(
|
|
179
|
-
this.tokens.access_token.split(".")[1],
|
|
180
|
-
"base64"
|
|
181
|
-
).toString()
|
|
182
|
-
);
|
|
183
|
-
return {
|
|
184
|
-
email: payload["tiime/userEmail"] || null,
|
|
185
|
-
expiresAt: new Date(this.tokens.expires_at)
|
|
186
|
-
};
|
|
187
|
-
} catch {
|
|
188
|
-
return { email: null, expiresAt: new Date(this.tokens.expires_at) };
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
isExpired() {
|
|
192
|
-
if (!this.tokens) return true;
|
|
193
|
-
return Date.now() >= this.tokens.expires_at - 6e4;
|
|
194
|
-
}
|
|
195
|
-
loadFromDisk() {
|
|
196
|
-
try {
|
|
197
|
-
if (existsSync(AUTH_FILE)) {
|
|
198
|
-
const data = JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
|
|
199
|
-
if (data.access_token && data.expires_at) {
|
|
200
|
-
this.tokens = data;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
} catch {
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
saveToDisk() {
|
|
207
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
208
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
209
|
-
}
|
|
210
|
-
writeFileSync(AUTH_FILE, JSON.stringify(this.tokens, null, 2));
|
|
211
|
-
}
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// src/client.ts
|
|
215
|
-
import { ofetch as ofetch2 } from "ofetch";
|
|
216
|
-
|
|
217
|
-
// src/errors.ts
|
|
218
|
-
var TiimeError = class extends Error {
|
|
219
|
-
constructor(message, status, endpoint, details) {
|
|
220
|
-
super(message);
|
|
221
|
-
this.status = status;
|
|
222
|
-
this.endpoint = endpoint;
|
|
223
|
-
this.details = details;
|
|
224
|
-
this.name = "TiimeError";
|
|
225
|
-
}
|
|
226
|
-
toJSON() {
|
|
227
|
-
return {
|
|
228
|
-
error: this.name,
|
|
229
|
-
message: this.message,
|
|
230
|
-
status: this.status,
|
|
231
|
-
endpoint: this.endpoint,
|
|
232
|
-
details: this.details
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
// src/resources/bank-accounts.ts
|
|
238
|
-
var BankAccountsResource = class {
|
|
239
|
-
constructor(fetch, companyId) {
|
|
240
|
-
this.fetch = fetch;
|
|
241
|
-
this.companyId = companyId;
|
|
242
|
-
}
|
|
243
|
-
list(enabled) {
|
|
244
|
-
return this.fetch(
|
|
245
|
-
`/companies/${this.companyId}/bank_accounts`,
|
|
246
|
-
{ query: enabled !== void 0 ? { enabled } : void 0 }
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
get(bankAccountId) {
|
|
250
|
-
return this.fetch(
|
|
251
|
-
`/companies/${this.companyId}/bank_accounts/${bankAccountId}`
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
async balance() {
|
|
255
|
-
const accounts = await this.list(true);
|
|
256
|
-
return accounts.map((a) => ({
|
|
257
|
-
name: a.name,
|
|
258
|
-
balance_amount: a.balance_amount,
|
|
259
|
-
currency: a.balance_currency
|
|
260
|
-
}));
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
// src/resources/bank-transactions.ts
|
|
265
|
-
var BankTransactionsResource = class {
|
|
266
|
-
constructor(fetch, companyId) {
|
|
267
|
-
this.fetch = fetch;
|
|
268
|
-
this.companyId = companyId;
|
|
269
|
-
}
|
|
270
|
-
list(params) {
|
|
271
|
-
const start = ((params?.page ?? 1) - 1) * (params?.pageSize ?? 100);
|
|
272
|
-
const end = start + (params?.pageSize ?? 100);
|
|
273
|
-
const { page: _, pageSize: __, from, to, search, ...query } = params ?? {};
|
|
274
|
-
if (from) query.transaction_date_start = from;
|
|
275
|
-
if (to) query.transaction_date_end = to;
|
|
276
|
-
if (search) query.wording = search;
|
|
277
|
-
return this.fetch(
|
|
278
|
-
`/companies/${this.companyId}/bank_transactions`,
|
|
279
|
-
{
|
|
280
|
-
query: { hide_refused: false, ...query },
|
|
281
|
-
headers: {
|
|
282
|
-
Accept: "application/vnd.tiime.bank_transactions.v2+json",
|
|
283
|
-
Range: `items=${start}-${end}`
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
async listAll(params) {
|
|
289
|
-
const pageSize = params?.pageSize ?? 200;
|
|
290
|
-
const all = [];
|
|
291
|
-
let page = 1;
|
|
292
|
-
let hasMore = true;
|
|
293
|
-
while (hasMore) {
|
|
294
|
-
const response = await this.list({ ...params, page, pageSize });
|
|
295
|
-
all.push(...response.transactions);
|
|
296
|
-
hasMore = response.transactions.length === pageSize;
|
|
297
|
-
page++;
|
|
298
|
-
}
|
|
299
|
-
return all;
|
|
300
|
-
}
|
|
301
|
-
unimputed() {
|
|
302
|
-
return this.fetch(
|
|
303
|
-
`/companies/${this.companyId}/bank_transactions/unimputed`
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
get(transactionId) {
|
|
307
|
-
return this.fetch(
|
|
308
|
-
`/companies/${this.companyId}/bank_transactions/${transactionId}`
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
labelSuggestions(transactionId) {
|
|
312
|
-
return this.fetch(
|
|
313
|
-
`/companies/${this.companyId}/bank_transactions/${transactionId}/label_suggestions`,
|
|
314
|
-
{
|
|
315
|
-
headers: {
|
|
316
|
-
Accept: "application/vnd.tiime.bank_transactions.label_suggestions.v2+json"
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
impute(transactionId, imputations) {
|
|
322
|
-
return this.fetch(
|
|
323
|
-
`/companies/${this.companyId}/bank_transactions/${transactionId}`,
|
|
324
|
-
{
|
|
325
|
-
method: "PATCH",
|
|
326
|
-
body: { imputations }
|
|
327
|
-
}
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
matchDocuments(transactionId, documentIds) {
|
|
331
|
-
return this.fetch(
|
|
332
|
-
`/companies/${this.companyId}/bank_transactions/${transactionId}/document_matchings`,
|
|
333
|
-
{
|
|
334
|
-
method: "PUT",
|
|
335
|
-
body: { documents: documentIds.map((id) => ({ id })) }
|
|
336
|
-
}
|
|
337
|
-
);
|
|
338
|
-
}
|
|
339
|
-
getMatchings(transactionId) {
|
|
340
|
-
return this.fetch(
|
|
341
|
-
`/companies/${this.companyId}/bank_transactions/${transactionId}/matchings`
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
|
|
346
|
-
// src/resources/clients.ts
|
|
347
|
-
var ClientsResource = class {
|
|
348
|
-
constructor(fetch, companyId) {
|
|
349
|
-
this.fetch = fetch;
|
|
350
|
-
this.companyId = companyId;
|
|
351
|
-
}
|
|
352
|
-
list(params) {
|
|
353
|
-
return this.fetch(`/companies/${this.companyId}/clients`, {
|
|
354
|
-
query: params,
|
|
355
|
-
headers: {
|
|
356
|
-
Accept: "application/vnd.tiime.timeline.v2+json",
|
|
357
|
-
Range: "items=0-*"
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
get(clientId) {
|
|
362
|
-
return this.fetch(
|
|
363
|
-
`/companies/${this.companyId}/clients/${clientId}`
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
create(params) {
|
|
367
|
-
return this.fetch(`/companies/${this.companyId}/clients`, {
|
|
368
|
-
method: "POST",
|
|
369
|
-
body: params
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
search(query) {
|
|
373
|
-
return this.fetch(`/companies/${this.companyId}/clients`, {
|
|
374
|
-
query: { search: query },
|
|
375
|
-
headers: {
|
|
376
|
-
Accept: "application/vnd.tiime.timeline.v2+json",
|
|
377
|
-
Range: "items=0-*"
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
// src/resources/company.ts
|
|
384
|
-
var CompanyResource = class {
|
|
385
|
-
constructor(fetch, companyId) {
|
|
386
|
-
this.fetch = fetch;
|
|
387
|
-
this.companyId = companyId;
|
|
388
|
-
}
|
|
389
|
-
get() {
|
|
390
|
-
return this.fetch(`/companies/${this.companyId}`);
|
|
391
|
-
}
|
|
392
|
-
users() {
|
|
393
|
-
return this.fetch(`/companies/${this.companyId}/users`);
|
|
394
|
-
}
|
|
395
|
-
appConfig() {
|
|
396
|
-
return this.fetch(`/companies/${this.companyId}/app_config`);
|
|
397
|
-
}
|
|
398
|
-
accountingPeriod(rangeYear = 1) {
|
|
399
|
-
return this.fetch(
|
|
400
|
-
`/companies/${this.companyId}/accounting_period/current`,
|
|
401
|
-
{ query: { range_year: rangeYear } }
|
|
402
|
-
);
|
|
403
|
-
}
|
|
404
|
-
tiles(keys) {
|
|
405
|
-
return this.fetch(`/companies/${this.companyId}/tiles`, {
|
|
406
|
-
query: { keys: keys.join(",") }
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
dashboardBlocks(displayGroup = "monitoring") {
|
|
410
|
-
return this.fetch(`/companies/${this.companyId}/dashboard_blocks`, {
|
|
411
|
-
query: { sorts: "rank:asc", display_group: displayGroup }
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
|
|
416
|
-
// src/resources/documents.ts
|
|
417
|
-
var DocumentsResource = class {
|
|
418
|
-
constructor(fetch, companyId) {
|
|
419
|
-
this.fetch = fetch;
|
|
420
|
-
this.companyId = companyId;
|
|
421
|
-
}
|
|
422
|
-
list(params) {
|
|
423
|
-
const start = ((params?.page ?? 1) - 1) * (params?.pageSize ?? 25);
|
|
424
|
-
const end = start + (params?.pageSize ?? 25);
|
|
425
|
-
const { page: _, pageSize: __, ...query } = params ?? {};
|
|
426
|
-
return this.fetch(`/companies/${this.companyId}/documents`, {
|
|
427
|
-
query: {
|
|
428
|
-
sorts: "created_at:desc",
|
|
429
|
-
expand: "file_family,preview_available",
|
|
430
|
-
...query
|
|
431
|
-
},
|
|
432
|
-
headers: {
|
|
433
|
-
Accept: "application/vnd.tiime.documents.v2+json,application/vnd.tiime.docs.query+json,application/vnd.tiime.docs.imputation+json",
|
|
434
|
-
Range: `items=${start}-${end}`
|
|
435
|
-
}
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
categories() {
|
|
439
|
-
return this.fetch(
|
|
440
|
-
`/companies/${this.companyId}/document_categories`,
|
|
441
|
-
{
|
|
442
|
-
headers: {
|
|
443
|
-
Accept: "application/vnd.tiime.documents.v3+json"
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
preview(documentId) {
|
|
449
|
-
return this.fetch(
|
|
450
|
-
`/companies/${this.companyId}/documents/${documentId}/preview`
|
|
451
|
-
);
|
|
452
|
-
}
|
|
453
|
-
upload(file, filename, type) {
|
|
454
|
-
const formData = new FormData();
|
|
455
|
-
formData.append("file", new Blob([file]), filename);
|
|
456
|
-
if (type) {
|
|
457
|
-
formData.append("type", type);
|
|
458
|
-
}
|
|
459
|
-
return this.fetch(`/companies/${this.companyId}/documents`, {
|
|
460
|
-
method: "POST",
|
|
461
|
-
body: formData
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
searchMatchable(query) {
|
|
465
|
-
return this.fetch(
|
|
466
|
-
`/companies/${this.companyId}/documents`,
|
|
467
|
-
{
|
|
468
|
-
query: { matchable: true, q: query },
|
|
469
|
-
headers: {
|
|
470
|
-
Accept: "application/vnd.tiime.documents.v3+json,application/vnd.tiime.docs.imputation+json",
|
|
471
|
-
Range: "items=0-25"
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
|
-
async download(documentId) {
|
|
477
|
-
return this.fetch(
|
|
478
|
-
`/companies/${this.companyId}/documents/${documentId}/download`,
|
|
479
|
-
{
|
|
480
|
-
headers: { Accept: "application/octet-stream" }
|
|
481
|
-
}
|
|
482
|
-
);
|
|
483
|
-
}
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
// src/resources/expense-reports.ts
|
|
487
|
-
var ExpenseReportsResource = class {
|
|
488
|
-
constructor(fetch, companyId) {
|
|
489
|
-
this.fetch = fetch;
|
|
490
|
-
this.companyId = companyId;
|
|
491
|
-
}
|
|
492
|
-
list(sorts = "metadata.date:desc") {
|
|
493
|
-
return this.fetch(
|
|
494
|
-
`/companies/${this.companyId}/expense_reports`,
|
|
495
|
-
{
|
|
496
|
-
query: { expand: "total_amount", sorts },
|
|
497
|
-
headers: { Range: "items=0-25" }
|
|
498
|
-
}
|
|
499
|
-
);
|
|
500
|
-
}
|
|
501
|
-
get(expenseReportId) {
|
|
502
|
-
return this.fetch(
|
|
503
|
-
`/companies/${this.companyId}/expense_reports/${expenseReportId}`
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
|
-
create(params) {
|
|
507
|
-
return this.fetch(
|
|
508
|
-
`/companies/${this.companyId}/expense_reports`,
|
|
509
|
-
{
|
|
510
|
-
method: "POST",
|
|
511
|
-
body: params
|
|
512
|
-
}
|
|
513
|
-
);
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
|
|
517
|
-
// src/resources/invoices.ts
|
|
518
|
-
var DEFAULT_INVOICE_TEMPLATE = {
|
|
519
|
-
template: "advanced",
|
|
520
|
-
status: "draft",
|
|
521
|
-
due_date_mode: "thirty_days",
|
|
522
|
-
title_enabled: true,
|
|
523
|
-
free_field_enabled: false,
|
|
524
|
-
free_field: "",
|
|
525
|
-
discount_enabled: false,
|
|
526
|
-
bank_detail_enabled: true,
|
|
527
|
-
payment_condition_enabled: true,
|
|
528
|
-
payment_condition: "En cas de retard de paiement, une p\xE9nalit\xE9 de 3 fois le taux d'int\xE9r\xEAt l\xE9gal sera appliqu\xE9e, \xE0 laquelle s'ajoutera une indemnit\xE9 forfaitaire pour frais de recouvrement de 40\u20AC.",
|
|
529
|
-
text_lines: []
|
|
530
|
-
};
|
|
531
|
-
var InvoicesResource = class {
|
|
532
|
-
constructor(fetch, companyId) {
|
|
533
|
-
this.fetch = fetch;
|
|
534
|
-
this.companyId = companyId;
|
|
535
|
-
}
|
|
536
|
-
list(params) {
|
|
537
|
-
const start = ((params?.page ?? 1) - 1) * (params?.pageSize ?? 25);
|
|
538
|
-
const end = start + (params?.pageSize ?? 25);
|
|
539
|
-
const query = {
|
|
540
|
-
sorts: params?.sorts ?? "invoice_number:desc"
|
|
541
|
-
};
|
|
542
|
-
if (params?.status) query.status = params.status;
|
|
543
|
-
return this.fetch(`/companies/${this.companyId}/invoices`, {
|
|
544
|
-
query,
|
|
545
|
-
headers: { Range: `items=${start}-${end}` }
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
async listAll(params) {
|
|
549
|
-
const pageSize = params?.pageSize ?? 100;
|
|
550
|
-
const all = [];
|
|
551
|
-
let page = 1;
|
|
552
|
-
let hasMore = true;
|
|
553
|
-
while (hasMore) {
|
|
554
|
-
const batch = await this.list({
|
|
555
|
-
sorts: params?.sorts,
|
|
556
|
-
status: params?.status,
|
|
557
|
-
page,
|
|
558
|
-
pageSize
|
|
559
|
-
});
|
|
560
|
-
all.push(...batch);
|
|
561
|
-
hasMore = batch.length === pageSize;
|
|
562
|
-
page++;
|
|
563
|
-
}
|
|
564
|
-
return all;
|
|
565
|
-
}
|
|
566
|
-
get(invoiceId) {
|
|
567
|
-
return this.fetch(
|
|
568
|
-
`/companies/${this.companyId}/invoices/${invoiceId}`
|
|
569
|
-
);
|
|
570
|
-
}
|
|
571
|
-
create(params) {
|
|
572
|
-
const body = { ...DEFAULT_INVOICE_TEMPLATE, ...params };
|
|
573
|
-
for (const line of body.lines ?? []) {
|
|
574
|
-
line.line_amount = line.quantity * line.unit_amount;
|
|
575
|
-
line.sequence ??= 1;
|
|
576
|
-
line.invoicing_category_type ??= "benefit";
|
|
577
|
-
line.discount_description ??= "";
|
|
578
|
-
line.discount_amount ??= null;
|
|
579
|
-
line.discount_percentage ??= null;
|
|
580
|
-
}
|
|
581
|
-
return this.fetch(`/companies/${this.companyId}/invoices`, {
|
|
582
|
-
method: "POST",
|
|
583
|
-
body
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
update(invoiceId, params) {
|
|
587
|
-
return this.fetch(
|
|
588
|
-
`/companies/${this.companyId}/invoices/${invoiceId}`,
|
|
589
|
-
{
|
|
590
|
-
method: "PUT",
|
|
591
|
-
body: params
|
|
592
|
-
}
|
|
593
|
-
);
|
|
594
|
-
}
|
|
595
|
-
send(invoiceId, params) {
|
|
596
|
-
return this.fetch(
|
|
597
|
-
`/companies/${this.companyId}/invoices/${invoiceId}/send`,
|
|
598
|
-
{
|
|
599
|
-
method: "POST",
|
|
600
|
-
body: params
|
|
601
|
-
}
|
|
602
|
-
);
|
|
603
|
-
}
|
|
604
|
-
async downloadPdf(invoiceId) {
|
|
605
|
-
return this.fetch(
|
|
606
|
-
`/companies/${this.companyId}/invoices/${invoiceId}/pdf`,
|
|
607
|
-
{
|
|
608
|
-
headers: { Accept: "application/pdf" }
|
|
609
|
-
}
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
delete(invoiceId) {
|
|
613
|
-
return this.fetch(
|
|
614
|
-
`/companies/${this.companyId}/invoices/${invoiceId}`,
|
|
615
|
-
{ method: "DELETE" }
|
|
616
|
-
);
|
|
617
|
-
}
|
|
618
|
-
async duplicate(invoiceId, overrides) {
|
|
619
|
-
const source = await this.get(invoiceId);
|
|
620
|
-
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
621
|
-
const lines = source.lines.map((l) => ({
|
|
622
|
-
description: l.description,
|
|
623
|
-
quantity: overrides?.quantity ?? l.quantity,
|
|
624
|
-
unit_amount: l.unit_amount,
|
|
625
|
-
vat_type: l.vat_type,
|
|
626
|
-
invoicing_unit: l.invoicing_unit,
|
|
627
|
-
invoicing_category_type: l.invoicing_category_type,
|
|
628
|
-
article: l.article
|
|
629
|
-
}));
|
|
630
|
-
return this.create({
|
|
631
|
-
client: source.client_id ? { id: source.client_id } : null,
|
|
632
|
-
emission_date: overrides?.emission_date ?? today,
|
|
633
|
-
title: source.title,
|
|
634
|
-
title_enabled: !!source.title,
|
|
635
|
-
lines,
|
|
636
|
-
status: "draft"
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
// src/resources/labels.ts
|
|
642
|
-
var LabelsResource = class {
|
|
643
|
-
constructor(fetch, companyId) {
|
|
644
|
-
this.fetch = fetch;
|
|
645
|
-
this.companyId = companyId;
|
|
646
|
-
}
|
|
647
|
-
list() {
|
|
648
|
-
return this.fetch(`/companies/${this.companyId}/labels`, {
|
|
649
|
-
headers: {
|
|
650
|
-
Accept: "application/vnd.tiime.labels.v2+json"
|
|
651
|
-
}
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
standard() {
|
|
655
|
-
return this.fetch(`/companies/${this.companyId}/standard_labels`);
|
|
656
|
-
}
|
|
657
|
-
tags() {
|
|
658
|
-
return this.fetch(`/companies/${this.companyId}/tags`, {
|
|
659
|
-
query: { expand: "tag_detail" }
|
|
660
|
-
});
|
|
661
|
-
}
|
|
662
|
-
};
|
|
663
|
-
|
|
664
|
-
// src/resources/quotations.ts
|
|
665
|
-
var QuotationsResource = class {
|
|
666
|
-
constructor(fetch, companyId) {
|
|
667
|
-
this.fetch = fetch;
|
|
668
|
-
this.companyId = companyId;
|
|
669
|
-
}
|
|
670
|
-
list(expand = "invoices") {
|
|
671
|
-
return this.fetch(`/companies/${this.companyId}/quotations`, {
|
|
672
|
-
query: { expand },
|
|
673
|
-
headers: { Range: "items=0-25" }
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
get(quotationId) {
|
|
677
|
-
return this.fetch(
|
|
678
|
-
`/companies/${this.companyId}/quotations/${quotationId}`
|
|
679
|
-
);
|
|
680
|
-
}
|
|
681
|
-
create(params) {
|
|
682
|
-
for (const line of params.lines ?? []) {
|
|
683
|
-
line.line_amount = line.quantity * line.unit_amount;
|
|
684
|
-
line.sequence ??= 1;
|
|
685
|
-
line.invoicing_category_type ??= "benefit";
|
|
686
|
-
line.discount_description ??= "";
|
|
687
|
-
line.discount_amount ??= null;
|
|
688
|
-
line.discount_percentage ??= null;
|
|
689
|
-
}
|
|
690
|
-
return this.fetch(`/companies/${this.companyId}/quotations`, {
|
|
691
|
-
method: "POST",
|
|
692
|
-
body: params
|
|
693
|
-
});
|
|
694
|
-
}
|
|
695
|
-
async downloadPdf(quotationId) {
|
|
696
|
-
return this.fetch(
|
|
697
|
-
`/companies/${this.companyId}/quotations/${quotationId}/pdf`,
|
|
698
|
-
{
|
|
699
|
-
headers: { Accept: "application/pdf" }
|
|
700
|
-
}
|
|
701
|
-
);
|
|
702
|
-
}
|
|
703
|
-
send(quotationId, params) {
|
|
704
|
-
return this.fetch(
|
|
705
|
-
`/companies/${this.companyId}/quotations/${quotationId}/send`,
|
|
706
|
-
{
|
|
707
|
-
method: "POST",
|
|
708
|
-
body: params
|
|
709
|
-
}
|
|
710
|
-
);
|
|
711
|
-
}
|
|
712
|
-
};
|
|
713
|
-
|
|
714
|
-
// src/resources/users.ts
|
|
715
|
-
var UsersResource = class {
|
|
716
|
-
constructor(fetch) {
|
|
717
|
-
this.fetch = fetch;
|
|
718
|
-
}
|
|
719
|
-
me() {
|
|
720
|
-
return this.fetch("/users/me");
|
|
721
|
-
}
|
|
722
|
-
legalInformations() {
|
|
723
|
-
return this.fetch("/users/me/legal_informations");
|
|
724
|
-
}
|
|
725
|
-
settings(companyId) {
|
|
726
|
-
return this.fetch(`/users/me/companies/${companyId}/settings`);
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
|
|
730
|
-
// src/client.ts
|
|
731
|
-
var BASE_URL = "https://chronos-api.tiime-apps.com/v1";
|
|
732
|
-
var TiimeClient = class {
|
|
733
|
-
fetch;
|
|
734
|
-
tokenManager;
|
|
735
|
-
companyId;
|
|
736
|
-
constructor(options = {}) {
|
|
737
|
-
this.companyId = resolveCompanyId(options.companyId);
|
|
738
|
-
this.tokenManager = options.tokenManager ?? new TokenManager({
|
|
739
|
-
tokens: options.tokens,
|
|
740
|
-
email: options.email,
|
|
741
|
-
password: options.password
|
|
742
|
-
});
|
|
743
|
-
this.fetch = ofetch2.create({
|
|
744
|
-
baseURL: BASE_URL,
|
|
745
|
-
retry: 2,
|
|
746
|
-
retryDelay: 500,
|
|
747
|
-
retryStatusCodes: [408, 429, 500, 502, 503, 504],
|
|
748
|
-
headers: {
|
|
749
|
-
"tiime-app": "tiime",
|
|
750
|
-
"tiime-app-version": "4.30.3",
|
|
751
|
-
"tiime-app-platform": "cli"
|
|
752
|
-
},
|
|
753
|
-
onRequest: async ({ options: options2 }) => {
|
|
754
|
-
const token = await this.tokenManager.getValidToken();
|
|
755
|
-
options2.headers.set("Authorization", `Bearer ${token}`);
|
|
756
|
-
},
|
|
757
|
-
onResponseError: ({ request, response }) => {
|
|
758
|
-
throw new TiimeError(
|
|
759
|
-
response.statusText || `HTTP ${response.status}`,
|
|
760
|
-
response.status,
|
|
761
|
-
String(request),
|
|
762
|
-
response._data
|
|
763
|
-
);
|
|
764
|
-
}
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
listCompanies() {
|
|
768
|
-
return this.fetch("/companies", {
|
|
769
|
-
headers: {
|
|
770
|
-
Accept: "application/vnd.tiime.companies.v2+json",
|
|
771
|
-
Range: "items=0-101"
|
|
772
|
-
}
|
|
773
|
-
});
|
|
774
|
-
}
|
|
775
|
-
get users() {
|
|
776
|
-
return new UsersResource(this.fetch);
|
|
777
|
-
}
|
|
778
|
-
get company() {
|
|
779
|
-
return new CompanyResource(this.fetch, this.companyId);
|
|
780
|
-
}
|
|
781
|
-
get clients() {
|
|
782
|
-
return new ClientsResource(this.fetch, this.companyId);
|
|
783
|
-
}
|
|
784
|
-
get invoices() {
|
|
785
|
-
return new InvoicesResource(this.fetch, this.companyId);
|
|
786
|
-
}
|
|
787
|
-
get quotations() {
|
|
788
|
-
return new QuotationsResource(this.fetch, this.companyId);
|
|
789
|
-
}
|
|
790
|
-
get bankAccounts() {
|
|
791
|
-
return new BankAccountsResource(this.fetch, this.companyId);
|
|
792
|
-
}
|
|
793
|
-
get bankTransactions() {
|
|
794
|
-
return new BankTransactionsResource(this.fetch, this.companyId);
|
|
795
|
-
}
|
|
796
|
-
get documents() {
|
|
797
|
-
return new DocumentsResource(this.fetch, this.companyId);
|
|
798
|
-
}
|
|
799
|
-
get expenseReports() {
|
|
800
|
-
return new ExpenseReportsResource(this.fetch, this.companyId);
|
|
801
|
-
}
|
|
802
|
-
get labels() {
|
|
803
|
-
return new LabelsResource(this.fetch, this.companyId);
|
|
804
|
-
}
|
|
805
|
-
};
|
|
806
|
-
export {
|
|
807
|
-
TiimeClient,
|
|
808
|
-
TiimeError,
|
|
809
|
-
TokenManager,
|
|
810
|
-
resolveCompanyId
|
|
811
|
-
};
|
|
1
|
+
import {execSync}from'child_process';import {existsSync,readFileSync,writeFileSync,mkdirSync}from'fs';import {homedir}from'os';import {join}from'path';var z=(s,e,t)=>{let n=new URL(e,s.endsWith("/")?s:`${s}/`);if(t)for(let[i,r]of Object.entries(t))r!=null&&n.searchParams.set(i,String(r));return n.href},U=s=>new Promise(e=>setTimeout(e,s)),J=s=>!!s?.includes("application/json")||!!s?.includes("+json"),D=s=>{let e=s.retry??0,t=s.retryDelay??500,n=new Set(s.retryStatusCodes??[]);return async(i,r)=>{let o=z(s.baseURL,i,r?.query),m=new Headers(s.headers);if(r?.headers)for(let[c,a]of Object.entries(r.headers))m.set(c,a);let u;r?.body!==void 0&&(r.body instanceof FormData?u=r.body:(m.set("Content-Type","application/json"),u=JSON.stringify(r.body))),s.onRequest&&await s.onRequest({options:{headers:m}});let h;for(let c=0;c<=e;c++){c>0&&await U(t);let a;try{a=await fetch(o,{method:r?.method??"GET",headers:m,body:u});}catch(l){if(h=l,c<e)continue;throw l}if(!a.ok&&n.has(a.status)&&(h=a,c<e))continue;if(!a.ok&&s.onResponseError){let l;try{l=await a.clone().json();}catch{}let L=Object.assign(a,{_data:l});s.onResponseError({request:o,response:L});}let R=a.headers.get("content-type");return a.status===204||!R?void 0:J(R)?a.json():a.arrayBuffer()}throw h}},q=async(s,e)=>{let t=await fetch(s,e);if(!t.ok)throw new Error(`HTTP ${t.status}: ${t.statusText}`);return t.json()};var Q="auth0.tiime.fr",G="iEbsbe3o66gcTBfGRa012kj1Rb6vjAND",K="https://chronos/",p=join(homedir(),".config","tiime"),f=join(p,"auth.json"),O=join(p,"config.json"),N="tiime-cli",B="tiime-credentials",V=(s,e)=>{try{let t=JSON.stringify({email:s,password:e});return execSync(`security add-generic-password -a "${N}" -s "${B}" -w '${t.replace(/'/g,"'\\''")}' -U`,{stdio:"ignore"}),!0}catch{return false}},W=()=>{try{let s=execSync(`security find-generic-password -a "${N}" -s "${B}" -w`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"]}).trim(),e=JSON.parse(s);return typeof e=="object"&&e!==null&&"email"in e&&"password"in e&&typeof e.email=="string"&&typeof e.password=="string"?e:null}catch{return null}},Y=(s,e)=>{existsSync(p)||mkdirSync(p,{recursive:true});let t=join(p,"credentials.json");writeFileSync(t,JSON.stringify({email:s,password:e},null,2),{mode:384});},X=()=>{try{let s=join(p,"credentials.json");if(existsSync(s)){let e=JSON.parse(readFileSync(s,"utf-8"));if(typeof e=="object"&&e!==null&&"email"in e&&"password"in e&&typeof e.email=="string"&&typeof e.password=="string")return e}}catch{}return null},Z=(s,e)=>{V(s,e)||Y(s,e);},ee=()=>W()??X(),A=s=>{if(s)return s;let e=process.env.TIIME_COMPANY_ID;if(e){let t=Number.parseInt(e,10);if(!Number.isNaN(t))return t}try{if(existsSync(O)){let t=JSON.parse(readFileSync(O,"utf-8"));if(t.companyId)return t.companyId}}catch{}throw new Error("No company ID configured. Set TIIME_COMPANY_ID env var, pass companyId option, or run `tiime company use --id <ID>`.")},y=class{tokens=null;credentials=null;persist;constructor(e={}){let t=e.tokens||e.email&&e.password;if(this.persist=e.persist??!t,e.tokens){this.tokens=e.tokens;return}if(e.email&&e.password){this.credentials={email:e.email,password:e.password};return}let n=process.env.TIIME_ACCESS_TOKEN;if(n){this.tokens={access_token:n,expires_at:Number.MAX_SAFE_INTEGER};return}let i=process.env.TIIME_EMAIL,r=process.env.TIIME_PASSWORD;if(i&&r){this.credentials={email:i,password:r};return}this.loadFromDisk();}async login(e,t){let n=await q(`https://${Q}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({grant_type:"password",client_id:G,audience:K,scope:"openid email",username:e,password:t})});return this.tokens={access_token:n.access_token,expires_at:Date.now()+n.expires_in*1e3},this.persist&&(this.saveToDisk(),Z(e,t)),this.tokens}async getValidToken(){if(!this.tokens||this.isExpired()){let e=this.credentials??ee();if(e)return (await this.login(e.email,e.password)).access_token;throw new Error(this.tokens?"Token expired. Provide credentials via options, TIIME_EMAIL/TIIME_PASSWORD env vars, or run `tiime auth login`.":"Not authenticated. Provide credentials via options, TIIME_EMAIL/TIIME_PASSWORD env vars, or run `tiime auth login`.")}return this.tokens.access_token}isAuthenticated(){return this.tokens!==null&&!this.isExpired()}logout(){this.tokens=null,existsSync(f)&&writeFileSync(f,"{}");}getTokenInfo(){if(!this.tokens)return {email:null,expiresAt:null};try{return {email:JSON.parse(Buffer.from(this.tokens.access_token.split(".")[1],"base64").toString())["tiime/userEmail"]||null,expiresAt:new Date(this.tokens.expires_at)}}catch{return {email:null,expiresAt:new Date(this.tokens.expires_at)}}}isExpired(){return this.tokens?Date.now()>=this.tokens.expires_at-6e4:true}loadFromDisk(){try{if(existsSync(f)){let e=JSON.parse(readFileSync(f,"utf-8"));e.access_token&&e.expires_at&&(this.tokens=e);}}catch{}}saveToDisk(){existsSync(p)||mkdirSync(p,{recursive:true}),writeFileSync(f,JSON.stringify(this.tokens,null,2));}};var b=class extends Error{constructor(t,n,i,r){super(t);this.status=n;this.endpoint=i;this.details=r;this.name="TiimeError";}toJSON(){return {error:this.name,message:this.message,status:this.status,endpoint:this.endpoint,details:this.details}}};var _=class{constructor(e,t){this.fetch=e;this.companyId=t;}list(e){return this.fetch(`/companies/${this.companyId}/bank_accounts`,{query:e!==void 0?{enabled:e}:void 0})}get(e){return this.fetch(`/companies/${this.companyId}/bank_accounts/${e}`)}async balance(){return (await this.list(true)).map(t=>({name:t.name,balance_amount:t.balance_amount,currency:t.balance_currency}))}};var I=class{constructor(e,t){this.fetch=e;this.companyId=t;}list(e){let t=((e?.page??1)-1)*(e?.pageSize??100),n=t+(e?.pageSize??100),{page:i,pageSize:r,from:o,to:m,search:u,...h}=e??{},c={...h};return o&&(c.transaction_date_start=o),m&&(c.transaction_date_end=m),u&&(c.wording=u),this.fetch(`/companies/${this.companyId}/bank_transactions`,{query:{hide_refused:false,...c},headers:{Accept:"application/vnd.tiime.bank_transactions.v2+json",Range:`items=${t}-${n}`}})}async listAll(e){let t=e?.pageSize??200,n=[],i=1,r=true;for(;r;){let o=await this.list({...e,page:i,pageSize:t});n.push(...o.transactions),r=o.transactions.length===t,i++;}return n}unimputed(){return this.fetch(`/companies/${this.companyId}/bank_transactions/unimputed`)}get(e){return this.fetch(`/companies/${this.companyId}/bank_transactions/${e}`)}labelSuggestions(e){return this.fetch(`/companies/${this.companyId}/bank_transactions/${e}/label_suggestions`,{headers:{Accept:"application/vnd.tiime.bank_transactions.label_suggestions.v2+json"}})}impute(e,t){return this.fetch(`/companies/${this.companyId}/bank_transactions/${e}`,{method:"PATCH",body:{imputations:t}})}matchDocuments(e,t){return this.fetch(`/companies/${this.companyId}/bank_transactions/${e}/document_matchings`,{method:"PUT",body:{documents:t.map(n=>({id:n}))}})}getMatchings(e){return this.fetch(`/companies/${this.companyId}/bank_transactions/${e}/matchings`)}};var v=class{constructor(e,t){this.fetch=e;this.companyId=t;}list(e){return this.fetch(`/companies/${this.companyId}/clients`,{query:e,headers:{Accept:"application/vnd.tiime.timeline.v2+json",Range:"items=0-*"}})}get(e){return this.fetch(`/companies/${this.companyId}/clients/${e}`)}create(e){return this.fetch(`/companies/${this.companyId}/clients`,{method:"POST",body:e})}search(e){return this.fetch(`/companies/${this.companyId}/clients`,{query:{search:e},headers:{Accept:"application/vnd.tiime.timeline.v2+json",Range:"items=0-*"}})}};var k=class{constructor(e,t){this.fetch=e;this.companyId=t;}get(){return this.fetch(`/companies/${this.companyId}`)}users(){return this.fetch(`/companies/${this.companyId}/users`)}appConfig(){return this.fetch(`/companies/${this.companyId}/app_config`)}accountingPeriod(e=1){return this.fetch(`/companies/${this.companyId}/accounting_period/current`,{query:{range_year:e}})}tiles(e){return this.fetch(`/companies/${this.companyId}/tiles`,{query:{keys:e.join(",")}})}dashboardBlocks(e="monitoring"){return this.fetch(`/companies/${this.companyId}/dashboard_blocks`,{query:{sorts:"rank:asc",display_group:e}})}};var w=class{constructor(e,t){this.fetch=e;this.companyId=t;}list(e){let t=((e?.page??1)-1)*(e?.pageSize??25),n=t+(e?.pageSize??25),{page:i,pageSize:r,...o}=e??{};return this.fetch(`/companies/${this.companyId}/documents`,{query:{sorts:"created_at:desc",expand:"file_family,preview_available",...o},headers:{Accept:"application/vnd.tiime.documents.v2+json,application/vnd.tiime.docs.query+json,application/vnd.tiime.docs.imputation+json",Range:`items=${t}-${n}`}})}categories(){return this.fetch(`/companies/${this.companyId}/document_categories`,{headers:{Accept:"application/vnd.tiime.documents.v3+json"}})}preview(e){return this.fetch(`/companies/${this.companyId}/documents/${e}/preview`)}upload(e,t,n){let i=new FormData;return i.append("file",new Blob([e]),t),n&&i.append("type",n),this.fetch(`/companies/${this.companyId}/documents`,{method:"POST",body:i})}searchMatchable(e){return this.fetch(`/companies/${this.companyId}/documents`,{query:{matchable:true,q:e},headers:{Accept:"application/vnd.tiime.documents.v3+json,application/vnd.tiime.docs.imputation+json",Range:"items=0-25"}})}async download(e){return this.fetch(`/companies/${this.companyId}/documents/${e}/download`,{headers:{Accept:"application/octet-stream"}})}};var T=class{constructor(e,t){this.fetch=e;this.companyId=t;}list(e="metadata.date:desc"){return this.fetch(`/companies/${this.companyId}/expense_reports`,{query:{expand:"total_amount",sorts:e},headers:{Range:"items=0-25"}})}get(e){return this.fetch(`/companies/${this.companyId}/expense_reports/${e}`)}create(e){return this.fetch(`/companies/${this.companyId}/expense_reports`,{method:"POST",body:e})}};var te={template:"advanced",status:"draft",due_date_mode:"thirty_days",title_enabled:true,free_field_enabled:false,free_field:"",discount_enabled:false,bank_detail_enabled:true,payment_condition_enabled:true,payment_condition:"En cas de retard de paiement, une p\xE9nalit\xE9 de 3 fois le taux d'int\xE9r\xEAt l\xE9gal sera appliqu\xE9e, \xE0 laquelle s'ajoutera une indemnit\xE9 forfaitaire pour frais de recouvrement de 40\u20AC.",text_lines:[]},P=class{constructor(e,t){this.fetch=e;this.companyId=t;}list(e){let t=((e?.page??1)-1)*(e?.pageSize??25),n=t+(e?.pageSize??25),i={sorts:e?.sorts??"invoice_number:desc"};return e?.status&&(i.status=e.status),this.fetch(`/companies/${this.companyId}/invoices`,{query:i,headers:{Range:`items=${t}-${n}`}})}async listAll(e){let t=e?.pageSize??100,n=[],i=1,r=true;for(;r;){let o=await this.list({sorts:e?.sorts,status:e?.status,page:i,pageSize:t});n.push(...o),r=o.length===t,i++;}return n}get(e){return this.fetch(`/companies/${this.companyId}/invoices/${e}`)}create(e){let t={...te,...e,lines:e.lines?.map(n=>({...n}))};for(let n of t.lines??[])n.line_amount=n.quantity*n.unit_amount,n.sequence??=1,n.invoicing_category_type??="benefit",n.discount_description??="",n.discount_amount??=null,n.discount_percentage??=null;return this.fetch(`/companies/${this.companyId}/invoices`,{method:"POST",body:t})}update(e,t){return this.fetch(`/companies/${this.companyId}/invoices/${e}`,{method:"PUT",body:t})}send(e,t){return this.fetch(`/companies/${this.companyId}/invoices/${e}/send`,{method:"POST",body:t})}async downloadPdf(e){return this.fetch(`/companies/${this.companyId}/invoices/${e}/pdf`,{headers:{Accept:"application/pdf"}})}delete(e){return this.fetch(`/companies/${this.companyId}/invoices/${e}`,{method:"DELETE"})}async duplicate(e,t){let n=await this.get(e),i=new Date().toISOString().split("T")[0],r=n.lines.map(o=>({description:o.description,quantity:t?.quantity??o.quantity,unit_amount:o.unit_amount,vat_type:o.vat_type,invoicing_unit:o.invoicing_unit,invoicing_category_type:o.invoicing_category_type,article:o.article}));return this.create({client:n.client_id?{id:n.client_id}:null,emission_date:t?.emission_date??i,title:n.title,title_enabled:!!n.title,lines:r,status:"draft"})}};var $=class{constructor(e,t){this.fetch=e;this.companyId=t;}list(){return this.fetch(`/companies/${this.companyId}/labels`,{headers:{Accept:"application/vnd.tiime.labels.v2+json"}})}standard(){return this.fetch(`/companies/${this.companyId}/standard_labels`)}tags(){return this.fetch(`/companies/${this.companyId}/tags`,{query:{expand:"tag_detail"}})}};var C=class{constructor(e,t){this.fetch=e;this.companyId=t;}list(e="invoices"){return this.fetch(`/companies/${this.companyId}/quotations`,{query:{expand:e},headers:{Range:"items=0-25"}})}get(e){return this.fetch(`/companies/${this.companyId}/quotations/${e}`)}create(e){let t={...e,lines:e.lines?.map(n=>({...n}))};for(let n of t.lines??[])n.line_amount=n.quantity*n.unit_amount,n.sequence??=1,n.invoicing_category_type??="benefit",n.discount_description??="",n.discount_amount??=null,n.discount_percentage??=null;return this.fetch(`/companies/${this.companyId}/quotations`,{method:"POST",body:t})}async downloadPdf(e){return this.fetch(`/companies/${this.companyId}/quotations/${e}/pdf`,{headers:{Accept:"application/pdf"}})}send(e,t){return this.fetch(`/companies/${this.companyId}/quotations/${e}/send`,{method:"POST",body:t})}};var F=class{constructor(e){this.fetch=e;}me(){return this.fetch("/users/me")}legalInformations(){return this.fetch("/users/me/legal_informations")}settings(e){return this.fetch(`/users/me/companies/${e}/settings`)}};var ne="https://chronos-api.tiime-apps.com/v1",E=class{fetch;tokenManager;companyId;constructor(e={}){this.companyId=A(e.companyId),this.tokenManager=e.tokenManager??new y({tokens:e.tokens,email:e.email,password:e.password}),this.fetch=D({baseURL:ne,retry:2,retryDelay:500,retryStatusCodes:[408,429,500,502,503,504],headers:{"tiime-app":"tiime","tiime-app-version":"4.30.3","tiime-app-platform":"cli"},onRequest:async({options:t})=>{let n=await this.tokenManager.getValidToken();t.headers.set("Authorization",`Bearer ${n}`);},onResponseError:({request:t,response:n})=>{throw new b(n.statusText||`HTTP ${n.status}`,n.status,String(t),n._data)}});}listCompanies(){return this.fetch("/companies",{headers:{Accept:"application/vnd.tiime.companies.v2+json",Range:"items=0-101"}})}get users(){return new F(this.fetch)}get company(){return new k(this.fetch,this.companyId)}get clients(){return new v(this.fetch,this.companyId)}get invoices(){return new P(this.fetch,this.companyId)}get quotations(){return new C(this.fetch,this.companyId)}get bankAccounts(){return new _(this.fetch,this.companyId)}get bankTransactions(){return new I(this.fetch,this.companyId)}get documents(){return new w(this.fetch,this.companyId)}get expenseReports(){return new T(this.fetch,this.companyId)}get labels(){return new $(this.fetch,this.companyId)}};
|
|
2
|
+
export{E as TiimeClient,b as TiimeError,y as TokenManager,A as resolveCompanyId};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiime-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "TypeScript SDK for Tiime accounting API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -44,9 +44,6 @@
|
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=20"
|
|
46
46
|
},
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"ofetch": "^1.5.1"
|
|
49
|
-
},
|
|
50
47
|
"devDependencies": {
|
|
51
48
|
"@biomejs/biome": "^2.4.6",
|
|
52
49
|
"@types/node": "^25.3.5",
|