timber-node 0.4.4 → 0.4.5

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 CHANGED
@@ -1,123 +1,123 @@
1
- # Timber SDK
2
-
3
- Official Node.js SDK for integrating with the Timber accounting backend API.
4
-
5
- Easily interact with Timber's core features like managing expenses, invoices, vendors, customers, payroll, and more using a unified SDK.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- npm install timber-node
11
- ```
12
-
13
- ## Getting Started
14
-
15
- ```typescript
16
- import { createClient } from 'timber-node';
17
-
18
- const client = createClient('your-api-key', {
19
- baseURL: 'https://api.timber.me', // optional
20
- });
21
-
22
- // Example: List expenses
23
- const expenses = await client.expense.list({ page: 1, limit: 10 });
24
- console.log(expenses.data);
25
- ```
26
-
27
- ## Authentication
28
-
29
- Timber uses API Key-based authentication. Generate this API key from your Timber profile developer settings.
30
-
31
- ```typescript
32
- const client = createClient('your-api-key');
33
- ```
34
-
35
- You can also load your API key from environment variables using `dotenv`.
36
-
37
- ## SDK Structure
38
-
39
- The SDK client exposes the following services:
40
-
41
- ```typescript
42
- client.expense;
43
- client.expenseCategory;
44
- client.rawExpense;
45
- client.invoice;
46
- client.invoicePayment;
47
- client.vendorPayment;
48
- client.billPayment;
49
- client.customer;
50
- client.taxRate;
51
- client.salary;
52
- client.employee;
53
- client.bankStatement;
54
- client.cheque;
55
- ```
56
-
57
- Each service provides common operations like `create`, `get`, `list`, `update`, and `delete` where applicable.
58
-
59
- ## Usage Examples
60
-
61
- ### Create an Expense
62
-
63
- ```typescript
64
- const response = await client.expense.create({
65
- type: 'Travel',
66
- merchant: 'Uber',
67
- category: 'Transportation',
68
- date: '2025-06-23',
69
- payment_method: 'cash',
70
- amount: 45.75,
71
- });
72
- console.log(response.data);
73
- ```
74
-
75
- ### List Expenses
76
-
77
- ```typescript
78
- const response = await client.expense.list({ page: 1, limit: 5 });
79
- console.log(response.data);
80
- ```
81
-
82
- ### Update an Expense
83
-
84
- ```typescript
85
- const updates = { amount: 50.0 };
86
- const response = await client.expense.update('expense_id_here', updates);
87
- console.log(response.data);
88
- ```
89
-
90
- ### Delete an Expense
91
-
92
- ```typescript
93
- const response = await client.expense.delete('expense_id_here');
94
- console.log(response.data.message);
95
- ```
96
-
97
- ## TypeScript Support
98
-
99
- The SDK includes full TypeScript support:
100
-
101
- ```typescript
102
- import type { Expense, CreateExpenseRequest } from 'timber-node';
103
- ```
104
-
105
- ## Error Handling
106
-
107
- Errors are returned as Axios errors:
108
-
109
- ```typescript
110
- import axios from 'axios';
111
-
112
- try {
113
- await client.expense.get('invalid-id');
114
- } catch (err) {
115
- if (axios.isAxiosError(err)) {
116
- console.error(err.response?.status, err.response?.data);
117
- }
118
- }
119
- ```
120
-
121
- ## Related Links
122
-
123
- - [Timber Website](https://timber.me)
1
+ # Timber SDK
2
+
3
+ Official Node.js SDK for integrating with the Timber accounting backend API.
4
+
5
+ Easily interact with Timber's core features like managing expenses, invoices, vendors, customers, payroll, and more using a unified SDK.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install timber-node
11
+ ```
12
+
13
+ ## Getting Started
14
+
15
+ ```typescript
16
+ import { createClient } from 'timber-node';
17
+
18
+ const client = createClient('your-api-key', {
19
+ baseURL: 'https://api.timber.me', // optional
20
+ });
21
+
22
+ // Example: List expenses
23
+ const expenses = await client.expense.list({ page: 1, limit: 10 });
24
+ console.log(expenses.data);
25
+ ```
26
+
27
+ ## Authentication
28
+
29
+ Timber uses API Key-based authentication. Generate this API key from your Timber profile developer settings.
30
+
31
+ ```typescript
32
+ const client = createClient('your-api-key');
33
+ ```
34
+
35
+ You can also load your API key from environment variables using `dotenv`.
36
+
37
+ ## SDK Structure
38
+
39
+ The SDK client exposes the following services:
40
+
41
+ ```typescript
42
+ client.expense;
43
+ client.expenseCategory;
44
+ client.rawExpense;
45
+ client.invoice;
46
+ client.invoicePayment;
47
+ client.vendorPayment;
48
+ client.billPayment;
49
+ client.customer;
50
+ client.taxRate;
51
+ client.salary;
52
+ client.employee;
53
+ client.bankStatement;
54
+ client.cheque;
55
+ ```
56
+
57
+ Each service provides common operations like `create`, `get`, `list`, `update`, and `delete` where applicable.
58
+
59
+ ## Usage Examples
60
+
61
+ ### Create an Expense
62
+
63
+ ```typescript
64
+ const response = await client.expense.create({
65
+ type: 'Travel',
66
+ merchant: 'Uber',
67
+ category: 'Transportation',
68
+ date: '2025-06-23',
69
+ payment_method: 'cash',
70
+ amount: 45.75,
71
+ });
72
+ console.log(response.data);
73
+ ```
74
+
75
+ ### List Expenses
76
+
77
+ ```typescript
78
+ const response = await client.expense.list({ page: 1, limit: 5 });
79
+ console.log(response.data);
80
+ ```
81
+
82
+ ### Update an Expense
83
+
84
+ ```typescript
85
+ const updates = { amount: 50.0 };
86
+ const response = await client.expense.update('expense_id_here', updates);
87
+ console.log(response.data);
88
+ ```
89
+
90
+ ### Delete an Expense
91
+
92
+ ```typescript
93
+ const response = await client.expense.delete('expense_id_here');
94
+ console.log(response.data.message);
95
+ ```
96
+
97
+ ## TypeScript Support
98
+
99
+ The SDK includes full TypeScript support:
100
+
101
+ ```typescript
102
+ import type { Expense, CreateExpenseRequest } from 'timber-node';
103
+ ```
104
+
105
+ ## Error Handling
106
+
107
+ Errors are returned as Axios errors:
108
+
109
+ ```typescript
110
+ import axios from 'axios';
111
+
112
+ try {
113
+ await client.expense.get('invalid-id');
114
+ } catch (err) {
115
+ if (axios.isAxiosError(err)) {
116
+ console.error(err.response?.status, err.response?.data);
117
+ }
118
+ }
119
+ ```
120
+
121
+ ## Related Links
122
+
123
+ - [Timber Website](https://timber.me)
package/dist/company.d.ts CHANGED
@@ -4,13 +4,26 @@ export interface CompanyData {
4
4
  currency: string;
5
5
  language: string;
6
6
  address: string;
7
+ address_details: Map<string, any>;
7
8
  city: string;
8
9
  state: string;
9
10
  zip_code: string;
10
- country: string;
11
+ country: {
12
+ _id: string;
13
+ name: string;
14
+ country_code: string;
15
+ currency: string;
16
+ timezone: string;
17
+ logo: string;
18
+ is_active: boolean;
19
+ created_at: string;
20
+ updated_at: string;
21
+ };
11
22
  email: string;
12
23
  country_code: string;
13
24
  mobile: string;
25
+ is_zakat: boolean;
26
+ zakat_number: string;
14
27
  tax_number: string;
15
28
  financial_start_date: string;
16
29
  license_expiry: string;
@@ -25,6 +38,7 @@ export interface CompanyData {
25
38
  license_number: string;
26
39
  license_authority: string;
27
40
  trn: string;
41
+ crn: string;
28
42
  }
29
43
  export interface Company extends CompanyData {
30
44
  _id: string;
@@ -8,6 +8,7 @@ export interface CustomerData {
8
8
  city: string;
9
9
  role: 'customer' | 'vendor' | 'biller';
10
10
  address: string;
11
+ address_details?: Record<string, string>;
11
12
  trn?: string;
12
13
  [key: string]: any;
13
14
  }
package/dist/customer.js CHANGED
@@ -46,17 +46,36 @@ class CustomerService {
46
46
  */
47
47
  async create(data) {
48
48
  const { formData, headers } = await (0, getFormData_1.getFormData)();
49
- Object.entries(data).forEach(([key, value]) => {
49
+ const appendFormData = (key, value) => {
50
+ if (value === undefined || value === null)
51
+ return;
50
52
  if (value instanceof File) {
51
53
  formData.append(key, value);
54
+ return;
52
55
  }
53
- else {
54
- formData.append(key, value);
56
+ if (Array.isArray(value)) {
57
+ value.forEach((item, index) => {
58
+ if (item instanceof File) {
59
+ formData.append(key, item);
60
+ }
61
+ else {
62
+ appendFormData(`${key}[${index}]`, item);
63
+ }
64
+ });
65
+ return;
55
66
  }
67
+ if (typeof value === 'object') {
68
+ Object.entries(value).forEach(([childKey, childValue]) => {
69
+ appendFormData(`${key}[${childKey}]`, childValue);
70
+ });
71
+ return;
72
+ }
73
+ formData.append(key, String(value));
74
+ };
75
+ Object.entries(data).forEach(([key, value]) => {
76
+ appendFormData(key, value);
56
77
  });
57
- return await this.http.post('/customer/customer', formData, {
58
- headers,
59
- });
78
+ return await this.http.post('/customer/customer', formData, { headers });
60
79
  }
61
80
  /**
62
81
  * Update an existing customer.
@@ -74,17 +93,36 @@ class CustomerService {
74
93
  */
75
94
  async update(id, data) {
76
95
  const { formData, headers } = await (0, getFormData_1.getFormData)();
77
- Object.entries(data).forEach(([key, value]) => {
96
+ const appendFormData = (key, value) => {
97
+ if (value === undefined || value === null)
98
+ return;
78
99
  if (value instanceof File) {
79
100
  formData.append(key, value);
101
+ return;
80
102
  }
81
- else {
82
- formData.append(key, value);
103
+ if (Array.isArray(value)) {
104
+ value.forEach((item, index) => {
105
+ if (item instanceof File) {
106
+ formData.append(key, item);
107
+ }
108
+ else {
109
+ appendFormData(`${key}[${index}]`, item);
110
+ }
111
+ });
112
+ return;
83
113
  }
114
+ if (typeof value === 'object') {
115
+ Object.entries(value).forEach(([childKey, childValue]) => {
116
+ appendFormData(`${key}[${childKey}]`, childValue);
117
+ });
118
+ return;
119
+ }
120
+ formData.append(key, String(value));
121
+ };
122
+ Object.entries(data).forEach(([key, value]) => {
123
+ appendFormData(key, value);
84
124
  });
85
- return await this.http.put(`/customer/customer/${id}`, formData, {
86
- headers,
87
- });
125
+ return await this.http.put(`/customer/customer/${id}`, formData, { headers });
88
126
  }
89
127
  /**
90
128
  * Delete an customer by ID.
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ import { ChequeService } from './cheque';
14
14
  import { BankStatementService } from './bankStatement';
15
15
  import { CompanyService } from './company';
16
16
  import { InvoiceNumberService } from './invoiceNumber';
17
- import { InvoiceTemplateService } from './invoiceTemplates';
17
+ import { InvoiceSettingsService } from './invoiceSettings';
18
18
  import { InvoiceItemService } from './invoiceItem';
19
19
  declare class TimberClient {
20
20
  auth: AuthService;
@@ -33,7 +33,7 @@ declare class TimberClient {
33
33
  bankStatement: BankStatementService;
34
34
  company: CompanyService;
35
35
  invoiceNumber: InvoiceNumberService;
36
- invoiceTemplate: InvoiceTemplateService;
36
+ invoiceSettings: InvoiceSettingsService;
37
37
  invoiceItem: InvoiceItemService;
38
38
  constructor(apiKey: string, options?: {
39
39
  baseURL?: string;
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ const cheque_1 = require("./cheque");
21
21
  const bankStatement_1 = require("./bankStatement");
22
22
  const company_1 = require("./company");
23
23
  const invoiceNumber_1 = require("./invoiceNumber");
24
- const invoiceTemplates_1 = require("./invoiceTemplates");
24
+ const invoiceSettings_1 = require("./invoiceSettings");
25
25
  const invoiceItem_1 = require("./invoiceItem");
26
26
  class TimberClient {
27
27
  constructor(apiKey, options = {}) {
@@ -60,7 +60,7 @@ class TimberClient {
60
60
  this.bankStatement = new bankStatement_1.BankStatementService(http);
61
61
  this.company = new company_1.CompanyService(http);
62
62
  this.invoiceNumber = new invoiceNumber_1.InvoiceNumberService(http);
63
- this.invoiceTemplate = new invoiceTemplates_1.InvoiceTemplateService(http);
63
+ this.invoiceSettings = new invoiceSettings_1.InvoiceSettingsService(http);
64
64
  this.invoiceItem = new invoiceItem_1.InvoiceItemService(http);
65
65
  }
66
66
  }
package/dist/invoice.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InvoiceService = void 0;
4
4
  const getFormData_1 = require("./utils/getFormData");
5
+ const convertToFormData_1 = require("./utils/convertToFormData");
5
6
  /**
6
7
  * Service for Invoice
7
8
  *
@@ -49,45 +50,41 @@ class InvoiceService {
49
50
  }
50
51
  async create(data) {
51
52
  const { formData, headers } = await (0, getFormData_1.getFormData)();
52
- for (const key in data) {
53
- const value = data[key];
54
- if (key === 'items' || key === 'customer' || key === 'biller') {
55
- formData.append(key, JSON.stringify(value));
56
- }
57
- else if (key === 'logo' && value && typeof value.pipe === 'function') {
58
- // This is a ReadStream
59
- formData.append('logo', value);
60
- }
61
- else if (value instanceof Date) {
62
- formData.append(key, value.toISOString());
63
- }
64
- else if (value !== undefined && value !== null) {
65
- formData.append(key, value.toString());
66
- }
67
- }
68
- return await this.http.post('/customer/invoice', formData, {
53
+ const formattedFormData = (0, convertToFormData_1.convertToFormData)(data, formData);
54
+ // for (const key in data) {
55
+ // const value = (data as any)[key];
56
+ // if (key === 'items' || key === 'customer' || key === 'biller') {
57
+ // formattedFormData.append(key, JSON.stringify(value));
58
+ // } else if (key === 'logo' && value && typeof value.pipe === 'function') {
59
+ // // This is a ReadStream
60
+ // formattedFormData.append('logo', value);
61
+ // } else if (value instanceof Date) {
62
+ // formattedFormData.append(key, value.toISOString());
63
+ // } else if (value !== undefined && value !== null) {
64
+ // formattedFormData.append(key, value.toString());
65
+ // }
66
+ // }
67
+ return await this.http.post('/customer/invoice', formattedFormData, {
69
68
  headers,
70
69
  });
71
70
  }
72
71
  async update(id, data) {
73
72
  const { formData, headers } = await (0, getFormData_1.getFormData)();
74
- for (const key in data) {
75
- const value = data[key];
76
- if (key === 'items' || key === 'customer' || key === 'biller') {
77
- formData.append(key, JSON.stringify(value));
78
- }
79
- else if (key === 'logo' && value && typeof value.pipe === 'function') {
80
- // This is a ReadStream
81
- formData.append('logo', value);
82
- }
83
- else if (value instanceof Date) {
84
- formData.append(key, value.toISOString());
85
- }
86
- else if (value !== undefined && value !== null) {
87
- formData.append(key, value.toString());
88
- }
89
- }
90
- return await this.http.put(`/customer/invoice/${id}`, data, {
73
+ const formattedFormData = (0, convertToFormData_1.convertToFormData)(data, formData);
74
+ // for (const key in data) {
75
+ // const value = (data as any)[key];
76
+ // if (key === 'items' || key === 'customer' || key === 'biller') {
77
+ // formattedFormData.append(key, JSON.stringify(value));
78
+ // } else if (key === 'logo' && value && typeof value.pipe === 'function') {
79
+ // // This is a ReadStream
80
+ // formattedFormData.append('logo', value);
81
+ // } else if (value instanceof Date) {
82
+ // formattedFormData.append(key, value.toISOString());
83
+ // } else if (value !== undefined && value !== null) {
84
+ // formattedFormData.append(key, value.toString());
85
+ // }
86
+ // }
87
+ return await this.http.put(`/customer/invoice/${id}`, formattedFormData, {
91
88
  headers,
92
89
  });
93
90
  }
@@ -1,5 +1,5 @@
1
1
  import { AxiosInstance, AxiosResponse } from 'axios';
2
- export interface CreateInvoiceTemplateRequest {
2
+ export interface CreateInvoiceSettingsRequest {
3
3
  terms: [
4
4
  {
5
5
  name: string;
@@ -14,8 +14,8 @@ export interface CreateInvoiceTemplateRequest {
14
14
  ];
15
15
  type?: 'terms' | 'notes';
16
16
  }
17
- export type UpdateInvoiceTemplateRequest = Partial<CreateInvoiceTemplateRequest>;
18
- export interface InvoiceTemplate {
17
+ export type UpdateInvoiceSettingsRequest = Partial<CreateInvoiceSettingsRequest>;
18
+ export interface InvoiceSettings {
19
19
  _id: string;
20
20
  company: string;
21
21
  terms: [
@@ -33,7 +33,7 @@ export interface InvoiceTemplate {
33
33
  created_at: string;
34
34
  updated_at: string;
35
35
  }
36
- export interface InvoiceTemplateQueryParams {
36
+ export interface InvoiceSettingsQueryParams {
37
37
  page?: number;
38
38
  limit?: number;
39
39
  sort?: string;
@@ -47,11 +47,11 @@ export interface InvoiceTemplateQueryParams {
47
47
  * ```ts
48
48
  * const { createClient } = require('timber-sdk-dev');
49
49
  * const client = createClient('your-api-key');
50
- * const InvoiceTemplate = await client.InvoiceTemplate.list({ page: 1, limit: 10 });
51
- * console.log(InvoiceTemplate.data);
50
+ * const InvoiceSettings = await client.InvoiceSettings.list({ page: 1, limit: 10 });
51
+ * console.log(InvoiceSettings.data);
52
52
  * ```
53
53
  */
54
- export declare class InvoiceTemplateService {
54
+ export declare class InvoiceSettingsService {
55
55
  private http;
56
56
  constructor(http: AxiosInstance);
57
57
  /**
@@ -61,11 +61,11 @@ export declare class InvoiceTemplateService {
61
61
  *
62
62
  * @example
63
63
  * ```ts
64
- * const invoiceTemplates = await client.InvoiceTemplate.list();
65
- * console.log(invoiceTemplates.data);
64
+ * const invoiceSettingss = await client.InvoiceSettings.list();
65
+ * console.log(invoiceSettingss.data);
66
66
  * ```
67
67
  */
68
- list(params: InvoiceTemplateQueryParams): Promise<AxiosResponse<InvoiceTemplate>>;
68
+ list(params: InvoiceSettingsQueryParams): Promise<AxiosResponse<InvoiceSettings>>;
69
69
  /**
70
70
  * Fetch a single invoice template by ID.
71
71
  *
@@ -74,10 +74,10 @@ export declare class InvoiceTemplateService {
74
74
  *
75
75
  * @example
76
76
  * ```ts
77
- * const invoiceTemplate = await client.InvoiceTemplate.get('invoice_template_id_here');
78
- * console.log(invoiceTemplate.data);
77
+ * const invoiceSettings = await client.InvoiceSettings.get('invoice_template_id_here');
78
+ * console.log(invoiceSettings.data);
79
79
  * ``` */
80
- get(id: string): Promise<AxiosResponse<InvoiceTemplate>>;
80
+ get(id: string): Promise<AxiosResponse<InvoiceSettings>>;
81
81
  /**
82
82
  * Create a new invoice template.
83
83
  *
@@ -86,7 +86,7 @@ export declare class InvoiceTemplateService {
86
86
  *
87
87
  * @example
88
88
  * ```ts
89
- * const newInvoiceTemplate = {
89
+ * const newInvoiceSettings = {
90
90
  * terms: [
91
91
  * {
92
92
  * name: "Terms",
@@ -100,11 +100,11 @@ export declare class InvoiceTemplateService {
100
100
  * }
101
101
  * ]
102
102
  * };
103
- * const response = await client.InvoiceTemplate.create(newInvoiceTemplate);
103
+ * const response = await client.InvoiceSettings.create(newInvoiceSettings);
104
104
  * console.log(response.data);
105
105
  * ```
106
106
  */
107
- create(data: CreateInvoiceTemplateRequest): Promise<AxiosResponse<InvoiceTemplate>>;
107
+ create(data: CreateInvoiceSettingsRequest): Promise<AxiosResponse<InvoiceSettings>>;
108
108
  /**
109
109
  * Update an existing invoice template.
110
110
  *
@@ -120,11 +120,11 @@ export declare class InvoiceTemplateService {
120
120
  * content: "Notes content"
121
121
  * }
122
122
  * ]};
123
- * const updated = await client.InvoiceTemplate.update('invoice_template_id_here', updates);
123
+ * const updated = await client.InvoiceSettings.update('invoice_template_id_here', updates);
124
124
  * console.log(updated.data);
125
125
  * ```
126
126
  */
127
- update(id: string, data: CreateInvoiceTemplateRequest): Promise<AxiosResponse<InvoiceTemplate>>;
127
+ update(id: string, data: CreateInvoiceSettingsRequest): Promise<AxiosResponse<InvoiceSettings>>;
128
128
  /**
129
129
  * Delete an invoice template by ID.
130
130
  *
@@ -133,7 +133,7 @@ export declare class InvoiceTemplateService {
133
133
  *
134
134
  * @example
135
135
  * ```ts
136
- * const response = await client.InvoiceTemplate.delete('expense_category_id_here');
136
+ * const response = await client.InvoiceSettings.delete('expense_category_id_here');
137
137
  * console.log(response.data.message);
138
138
  * ```
139
139
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InvoiceTemplateService = void 0;
3
+ exports.InvoiceSettingsService = void 0;
4
4
  /**
5
5
  * Service for Invoice Template
6
6
  *
@@ -8,11 +8,11 @@ exports.InvoiceTemplateService = void 0;
8
8
  * ```ts
9
9
  * const { createClient } = require('timber-sdk-dev');
10
10
  * const client = createClient('your-api-key');
11
- * const InvoiceTemplate = await client.InvoiceTemplate.list({ page: 1, limit: 10 });
12
- * console.log(InvoiceTemplate.data);
11
+ * const InvoiceSettings = await client.InvoiceSettings.list({ page: 1, limit: 10 });
12
+ * console.log(InvoiceSettings.data);
13
13
  * ```
14
14
  */
15
- class InvoiceTemplateService {
15
+ class InvoiceSettingsService {
16
16
  constructor(http) {
17
17
  this.http = http;
18
18
  }
@@ -23,12 +23,12 @@ class InvoiceTemplateService {
23
23
  *
24
24
  * @example
25
25
  * ```ts
26
- * const invoiceTemplates = await client.InvoiceTemplate.list();
27
- * console.log(invoiceTemplates.data);
26
+ * const invoiceSettingss = await client.InvoiceSettings.list();
27
+ * console.log(invoiceSettingss.data);
28
28
  * ```
29
29
  */
30
30
  async list(params) {
31
- return await this.http.get('/customer/invoice-template', {
31
+ return await this.http.get('/customer/invoice-settings', {
32
32
  params,
33
33
  });
34
34
  }
@@ -40,11 +40,11 @@ class InvoiceTemplateService {
40
40
  *
41
41
  * @example
42
42
  * ```ts
43
- * const invoiceTemplate = await client.InvoiceTemplate.get('invoice_template_id_here');
44
- * console.log(invoiceTemplate.data);
43
+ * const invoiceSettings = await client.InvoiceSettings.get('invoice_template_id_here');
44
+ * console.log(invoiceSettings.data);
45
45
  * ``` */
46
46
  async get(id) {
47
- return await this.http.get(`/customer/invoice-template/${id}`);
47
+ return await this.http.get(`/customer/invoice-settings/${id}`);
48
48
  }
49
49
  /**
50
50
  * Create a new invoice template.
@@ -54,7 +54,7 @@ class InvoiceTemplateService {
54
54
  *
55
55
  * @example
56
56
  * ```ts
57
- * const newInvoiceTemplate = {
57
+ * const newInvoiceSettings = {
58
58
  * terms: [
59
59
  * {
60
60
  * name: "Terms",
@@ -68,12 +68,12 @@ class InvoiceTemplateService {
68
68
  * }
69
69
  * ]
70
70
  * };
71
- * const response = await client.InvoiceTemplate.create(newInvoiceTemplate);
71
+ * const response = await client.InvoiceSettings.create(newInvoiceSettings);
72
72
  * console.log(response.data);
73
73
  * ```
74
74
  */
75
75
  async create(data) {
76
- return await this.http.post('/customer/invoice-template', data);
76
+ return await this.http.post('/customer/invoice-settings', data);
77
77
  }
78
78
  /**
79
79
  * Update an existing invoice template.
@@ -90,12 +90,12 @@ class InvoiceTemplateService {
90
90
  * content: "Notes content"
91
91
  * }
92
92
  * ]};
93
- * const updated = await client.InvoiceTemplate.update('invoice_template_id_here', updates);
93
+ * const updated = await client.InvoiceSettings.update('invoice_template_id_here', updates);
94
94
  * console.log(updated.data);
95
95
  * ```
96
96
  */
97
97
  async update(id, data) {
98
- return await this.http.put(`/customer/invoice-template/${id}`, data);
98
+ return await this.http.put(`/customer/invoice-settings/${id}`, data);
99
99
  }
100
100
  /**
101
101
  * Delete an invoice template by ID.
@@ -105,12 +105,12 @@ class InvoiceTemplateService {
105
105
  *
106
106
  * @example
107
107
  * ```ts
108
- * const response = await client.InvoiceTemplate.delete('expense_category_id_here');
108
+ * const response = await client.InvoiceSettings.delete('expense_category_id_here');
109
109
  * console.log(response.data.message);
110
110
  * ```
111
111
  */
112
112
  async delete(id) {
113
- return await this.http.delete(`/customer/invoice-template/${id}`);
113
+ return await this.http.delete(`/customer/invoice-settings/${id}`);
114
114
  }
115
115
  }
116
- exports.InvoiceTemplateService = InvoiceTemplateService;
116
+ exports.InvoiceSettingsService = InvoiceSettingsService;
package/dist/taxRate.d.ts CHANGED
@@ -8,6 +8,7 @@ export interface TaxRateData {
8
8
  type: string;
9
9
  [key: string]: any;
10
10
  }
11
+ export type TaxRateType = 'SALES' | 'PURCHASES';
11
12
  export interface TaxRate extends TaxRateData {
12
13
  _id: string;
13
14
  createdAt?: string;
@@ -16,16 +17,37 @@ export interface TaxRate extends TaxRateData {
16
17
  export interface TaxRateQueryParams {
17
18
  page?: number;
18
19
  limit?: number;
20
+ type?: TaxRateType;
19
21
  }
20
22
  /**
21
23
  * Service for Tax Rate
22
24
  *
25
+ * @remarks
26
+ * The `type` parameter is mandatory and determines the tax context:
27
+ *
28
+ * - `SALES` → Use this when creating or displaying **customer invoices**
29
+ * - `PURCHASES` → Use this when creating or displaying **vendor payments / expenses**
30
+ *
23
31
  * @example
24
32
  * ```ts
25
33
  * const { createClient } = require('timber-sdk-dev');
26
34
  * const client = createClient('your-api-key');
27
- * const taxRate = await client.taxRate.list({ page: 1, limit: 10 });
28
- * console.log(taxRate.data);
35
+ *
36
+ * // Fetch tax rates for invoices
37
+ * const salesTaxes = await client.taxRate.list({
38
+ * page: 1,
39
+ * limit: 10,
40
+ * type: 'SALES'
41
+ * });
42
+ *
43
+ * // Fetch tax rates for vendor payments
44
+ * const purchaseTaxes = await client.taxRate.list({
45
+ * page: 1,
46
+ * limit: 10,
47
+ * type: 'PURCHASES'
48
+ * });
49
+ *
50
+ * console.log(salesTaxes.data);
29
51
  * ```
30
52
  */
31
53
  export declare class TaxRateService {
package/dist/taxRate.js CHANGED
@@ -4,12 +4,32 @@ exports.TaxRateService = void 0;
4
4
  /**
5
5
  * Service for Tax Rate
6
6
  *
7
+ * @remarks
8
+ * The `type` parameter is mandatory and determines the tax context:
9
+ *
10
+ * - `SALES` → Use this when creating or displaying **customer invoices**
11
+ * - `PURCHASES` → Use this when creating or displaying **vendor payments / expenses**
12
+ *
7
13
  * @example
8
14
  * ```ts
9
15
  * const { createClient } = require('timber-sdk-dev');
10
16
  * const client = createClient('your-api-key');
11
- * const taxRate = await client.taxRate.list({ page: 1, limit: 10 });
12
- * console.log(taxRate.data);
17
+ *
18
+ * // Fetch tax rates for invoices
19
+ * const salesTaxes = await client.taxRate.list({
20
+ * page: 1,
21
+ * limit: 10,
22
+ * type: 'SALES'
23
+ * });
24
+ *
25
+ * // Fetch tax rates for vendor payments
26
+ * const purchaseTaxes = await client.taxRate.list({
27
+ * page: 1,
28
+ * limit: 10,
29
+ * type: 'PURCHASES'
30
+ * });
31
+ *
32
+ * console.log(salesTaxes.data);
13
33
  * ```
14
34
  */
15
35
  class TaxRateService {
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Converts a nested object to FormData
3
+ * @param obj - The object to convert
4
+ * @param formData - The FormData instance (optional, creates new if not provided)
5
+ * @param parentKey - The parent key for nested properties (used internally)
6
+ * @returns FormData instance
7
+ */
8
+ export declare function convertToFormData(obj: any, formData?: FormData, parentKey?: string): FormData;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertToFormData = convertToFormData;
4
+ /**
5
+ * Converts a nested object to FormData
6
+ * @param obj - The object to convert
7
+ * @param formData - The FormData instance (optional, creates new if not provided)
8
+ * @param parentKey - The parent key for nested properties (used internally)
9
+ * @returns FormData instance
10
+ */
11
+ function convertToFormData(obj, formData = new FormData(), parentKey = '') {
12
+ if (obj === null || obj === undefined) {
13
+ return formData;
14
+ }
15
+ Object.keys(obj).forEach(key => {
16
+ const value = obj[key];
17
+ const formKey = parentKey ? `${parentKey}[${key}]` : key;
18
+ // Handle null or undefined values - skip them
19
+ if (value === null || value === undefined) {
20
+ formData.append(formKey, '');
21
+ return;
22
+ }
23
+ // Handle File objects
24
+ if (value instanceof File) {
25
+ formData.append(formKey, value);
26
+ }
27
+ // Handle Blob objects
28
+ else if (value instanceof Blob) {
29
+ formData.append(formKey, value);
30
+ }
31
+ // Handle Date objects
32
+ else if (value instanceof Date) {
33
+ formData.append(formKey, value.toISOString());
34
+ }
35
+ // Handle Arrays
36
+ else if (Array.isArray(value)) {
37
+ // Handle empty arrays - mark them so backend can reconstruct
38
+ if (value.length === 0) {
39
+ formData.append(formKey, '[]');
40
+ return;
41
+ }
42
+ value.forEach((item, index) => {
43
+ const arrayKey = `${formKey}[${index}]`;
44
+ // If array item is an object, recurse
45
+ if (typeof item === 'object' &&
46
+ item !== null &&
47
+ !(item instanceof File) &&
48
+ !(item instanceof Blob)) {
49
+ convertToFormData(item, formData, arrayKey);
50
+ }
51
+ // If array item is a primitive or File/Blob, append with indexed key
52
+ else if (item !== null && item !== undefined) {
53
+ formData.append(arrayKey, item);
54
+ }
55
+ });
56
+ }
57
+ // Handle nested objects (but not File/Blob/Date)
58
+ else if (typeof value === 'object' &&
59
+ !(value instanceof File) &&
60
+ !(value instanceof Blob) &&
61
+ !(value instanceof Date)) {
62
+ convertToFormData(value, formData, formKey);
63
+ }
64
+ // Handle primitives (string, number, boolean)
65
+ else {
66
+ // Convert booleans and numbers to strings
67
+ formData.append(formKey, String(value));
68
+ }
69
+ });
70
+ return formData;
71
+ }
package/package.json CHANGED
@@ -1,63 +1,63 @@
1
- {
2
- "name": "timber-node",
3
- "version": "0.4.4",
4
- "description": "Simplifying accounting and tax filing for businesses",
5
- "keywords": [
6
- "timber"
7
- ],
8
- "homepage": "https://github.com/TImber-UAE/timber-be-sdk-s#readme",
9
- "bugs": {
10
- "url": "https://github.com/TImber-UAE/timber-be-sdk-s/issues"
11
- },
12
- "repository": {
13
- "type": "git",
14
- "url": "git+https://github.com/TImber-UAE/timber-be-sdk-s.git"
15
- },
16
- "license": "MIT",
17
- "author": "timberaccounting",
18
- "main": "dist/index.js",
19
- "types": "dist/index.d.ts",
20
- "exports": {
21
- ".": {
22
- "require": "./dist/index.js",
23
- "default": "./dist/index.js"
24
- }
25
- },
26
- "scripts": {
27
- "dev": "nodemon src/index.js",
28
- "build": "tsc",
29
- "docs": "typedoc",
30
- "prepare": "husky",
31
- "lint": "eslint . --ext .ts,.js",
32
- "lint:fix": "eslint . --ext .ts,.js --fix"
33
- },
34
- "lint-staged": {
35
- "*.{js,ts,json,md}": [
36
- "prettier --write",
37
- "eslint --fix"
38
- ]
39
- },
40
- "dependencies": {
41
- "axios": "^1.10.0",
42
- "form-data": "^4.0.3",
43
- "timber-node": "^0.0.5",
44
- "typescript-eslint": "^8.35.0"
45
- },
46
- "devDependencies": {
47
- "@commitlint/cli": "^19.8.1",
48
- "@commitlint/config-conventional": "^19.8.1",
49
- "@types/node": "^24.0.4",
50
- "@typescript-eslint/eslint-plugin": "^8.35.0",
51
- "@typescript-eslint/parser": "^8.35.0",
52
- "eslint": "^9.29.0",
53
- "eslint-config-prettier": "^10.1.5",
54
- "eslint-plugin-prettier": "^5.5.1",
55
- "globals": "^16.2.0",
56
- "husky": "^8.0.3",
57
- "nodemon": "^3.1.10",
58
- "prettier": "^3.6.2",
59
- "typedoc": "^0.28.5",
60
- "typedoc-plugin-markdown": "^4.7.0",
61
- "typescript": "^5.8.3"
62
- }
63
- }
1
+ {
2
+ "name": "timber-node",
3
+ "version": "0.4.5",
4
+ "description": "Simplifying accounting and tax filing for businesses",
5
+ "keywords": [
6
+ "timber"
7
+ ],
8
+ "homepage": "https://github.com/TImber-UAE/timber-be-sdk-s#readme",
9
+ "bugs": {
10
+ "url": "https://github.com/TImber-UAE/timber-be-sdk-s/issues"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/TImber-UAE/timber-be-sdk-s.git"
15
+ },
16
+ "license": "MIT",
17
+ "author": "timberaccounting",
18
+ "main": "dist/index.js",
19
+ "types": "dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "require": "./dist/index.js",
23
+ "default": "./dist/index.js"
24
+ }
25
+ },
26
+ "scripts": {
27
+ "dev": "nodemon src/index.js",
28
+ "build": "tsc",
29
+ "docs": "typedoc",
30
+ "prepare": "husky",
31
+ "lint": "eslint . --ext .ts,.js",
32
+ "lint:fix": "eslint . --ext .ts,.js --fix"
33
+ },
34
+ "lint-staged": {
35
+ "*.{js,ts,json,md}": [
36
+ "prettier --write",
37
+ "eslint --fix"
38
+ ]
39
+ },
40
+ "dependencies": {
41
+ "axios": "^1.10.0",
42
+ "form-data": "^4.0.3",
43
+ "timber-node": "^0.0.5",
44
+ "typescript-eslint": "^8.35.0"
45
+ },
46
+ "devDependencies": {
47
+ "@commitlint/cli": "^19.8.1",
48
+ "@commitlint/config-conventional": "^19.8.1",
49
+ "@types/node": "^24.0.4",
50
+ "@typescript-eslint/eslint-plugin": "^8.35.0",
51
+ "@typescript-eslint/parser": "^8.35.0",
52
+ "eslint": "^9.29.0",
53
+ "eslint-config-prettier": "^10.1.5",
54
+ "eslint-plugin-prettier": "^5.5.1",
55
+ "globals": "^16.2.0",
56
+ "husky": "^8.0.3",
57
+ "nodemon": "^3.1.10",
58
+ "prettier": "^3.6.2",
59
+ "typedoc": "^0.28.5",
60
+ "typedoc-plugin-markdown": "^4.7.0",
61
+ "typescript": "^5.8.3"
62
+ }
63
+ }