@promptpartner/bexio-mcp-server 2.0.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/LICENSE +21 -0
- package/README.md +161 -0
- package/dist/bexio-client.d.ts +350 -0
- package/dist/bexio-client.js +1045 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +80 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.js +28 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.js +81 -0
- package/dist/shared/errors.d.ts +21 -0
- package/dist/shared/errors.js +54 -0
- package/dist/shared/index.d.ts +5 -0
- package/dist/shared/index.js +5 -0
- package/dist/shared/response.d.ts +24 -0
- package/dist/shared/response.js +92 -0
- package/dist/tools/accounting/definitions.d.ts +9 -0
- package/dist/tools/accounting/definitions.js +345 -0
- package/dist/tools/accounting/handlers.d.ts +10 -0
- package/dist/tools/accounting/handlers.js +121 -0
- package/dist/tools/accounting/index.d.ts +16 -0
- package/dist/tools/accounting/index.js +16 -0
- package/dist/tools/banking/definitions.d.ts +11 -0
- package/dist/tools/banking/definitions.js +349 -0
- package/dist/tools/banking/handlers.d.ts +9 -0
- package/dist/tools/banking/handlers.js +123 -0
- package/dist/tools/banking/index.d.ts +6 -0
- package/dist/tools/banking/index.js +6 -0
- package/dist/tools/company/definitions.d.ts +7 -0
- package/dist/tools/company/definitions.js +87 -0
- package/dist/tools/company/handlers.d.ts +7 -0
- package/dist/tools/company/handlers.js +31 -0
- package/dist/tools/company/index.d.ts +6 -0
- package/dist/tools/company/index.js +6 -0
- package/dist/tools/contacts/definitions.d.ts +6 -0
- package/dist/tools/contacts/definitions.js +150 -0
- package/dist/tools/contacts/handlers.d.ts +7 -0
- package/dist/tools/contacts/handlers.js +40 -0
- package/dist/tools/contacts/index.d.ts +6 -0
- package/dist/tools/contacts/index.js +5 -0
- package/dist/tools/deliveries/definitions.d.ts +6 -0
- package/dist/tools/deliveries/definitions.js +67 -0
- package/dist/tools/deliveries/handlers.d.ts +7 -0
- package/dist/tools/deliveries/handlers.js +28 -0
- package/dist/tools/deliveries/index.d.ts +6 -0
- package/dist/tools/deliveries/index.js +5 -0
- package/dist/tools/files/definitions.d.ts +6 -0
- package/dist/tools/files/definitions.js +217 -0
- package/dist/tools/files/handlers.d.ts +7 -0
- package/dist/tools/files/handlers.js +63 -0
- package/dist/tools/files/index.d.ts +6 -0
- package/dist/tools/files/index.js +5 -0
- package/dist/tools/index.d.ts +19 -0
- package/dist/tools/index.js +93 -0
- package/dist/tools/invoices/definitions.d.ts +6 -0
- package/dist/tools/invoices/definitions.js +147 -0
- package/dist/tools/invoices/handlers.d.ts +7 -0
- package/dist/tools/invoices/handlers.js +119 -0
- package/dist/tools/invoices/index.d.ts +6 -0
- package/dist/tools/invoices/index.js +5 -0
- package/dist/tools/items/definitions.d.ts +6 -0
- package/dist/tools/items/definitions.js +100 -0
- package/dist/tools/items/handlers.d.ts +7 -0
- package/dist/tools/items/handlers.js +36 -0
- package/dist/tools/items/index.d.ts +6 -0
- package/dist/tools/items/index.js +5 -0
- package/dist/tools/misc/definitions.d.ts +6 -0
- package/dist/tools/misc/definitions.js +126 -0
- package/dist/tools/misc/handlers.d.ts +7 -0
- package/dist/tools/misc/handlers.js +52 -0
- package/dist/tools/misc/index.d.ts +6 -0
- package/dist/tools/misc/index.js +5 -0
- package/dist/tools/orders/definitions.d.ts +6 -0
- package/dist/tools/orders/definitions.js +114 -0
- package/dist/tools/orders/handlers.d.ts +7 -0
- package/dist/tools/orders/handlers.js +62 -0
- package/dist/tools/orders/index.d.ts +6 -0
- package/dist/tools/orders/index.js +5 -0
- package/dist/tools/payments/definitions.d.ts +6 -0
- package/dist/tools/payments/definitions.js +74 -0
- package/dist/tools/payments/handlers.d.ts +7 -0
- package/dist/tools/payments/handlers.js +28 -0
- package/dist/tools/payments/index.d.ts +6 -0
- package/dist/tools/payments/index.js +5 -0
- package/dist/tools/payroll/definitions.d.ts +15 -0
- package/dist/tools/payroll/definitions.js +239 -0
- package/dist/tools/payroll/handlers.d.ts +14 -0
- package/dist/tools/payroll/handlers.js +152 -0
- package/dist/tools/payroll/index.d.ts +16 -0
- package/dist/tools/payroll/index.js +16 -0
- package/dist/tools/projects/definitions.d.ts +7 -0
- package/dist/tools/projects/definitions.js +430 -0
- package/dist/tools/projects/handlers.d.ts +7 -0
- package/dist/tools/projects/handlers.js +127 -0
- package/dist/tools/projects/index.d.ts +6 -0
- package/dist/tools/projects/index.js +6 -0
- package/dist/tools/purchase/definitions.d.ts +6 -0
- package/dist/tools/purchase/definitions.js +381 -0
- package/dist/tools/purchase/handlers.d.ts +7 -0
- package/dist/tools/purchase/handlers.js +120 -0
- package/dist/tools/purchase/index.d.ts +7 -0
- package/dist/tools/purchase/index.js +6 -0
- package/dist/tools/quotes/definitions.d.ts +6 -0
- package/dist/tools/quotes/definitions.js +174 -0
- package/dist/tools/quotes/handlers.d.ts +7 -0
- package/dist/tools/quotes/handlers.js +79 -0
- package/dist/tools/quotes/index.d.ts +6 -0
- package/dist/tools/quotes/index.js +5 -0
- package/dist/tools/reference/definitions.d.ts +7 -0
- package/dist/tools/reference/definitions.js +421 -0
- package/dist/tools/reference/handlers.d.ts +7 -0
- package/dist/tools/reference/handlers.js +161 -0
- package/dist/tools/reference/index.d.ts +6 -0
- package/dist/tools/reference/index.js +6 -0
- package/dist/tools/reminders/definitions.d.ts +6 -0
- package/dist/tools/reminders/definitions.js +132 -0
- package/dist/tools/reminders/handlers.d.ts +7 -0
- package/dist/tools/reminders/handlers.js +43 -0
- package/dist/tools/reminders/index.d.ts +6 -0
- package/dist/tools/reminders/index.js +5 -0
- package/dist/tools/reports/definitions.d.ts +6 -0
- package/dist/tools/reports/definitions.js +133 -0
- package/dist/tools/reports/handlers.d.ts +7 -0
- package/dist/tools/reports/handlers.js +33 -0
- package/dist/tools/reports/index.d.ts +6 -0
- package/dist/tools/reports/index.js +5 -0
- package/dist/tools/timetracking/definitions.d.ts +9 -0
- package/dist/tools/timetracking/definitions.js +226 -0
- package/dist/tools/timetracking/handlers.d.ts +9 -0
- package/dist/tools/timetracking/handlers.js +88 -0
- package/dist/tools/timetracking/index.d.ts +6 -0
- package/dist/tools/timetracking/index.js +6 -0
- package/dist/tools/users/definitions.d.ts +6 -0
- package/dist/tools/users/definitions.js +93 -0
- package/dist/tools/users/handlers.d.ts +7 -0
- package/dist/tools/users/handlers.js +35 -0
- package/dist/tools/users/index.d.ts +6 -0
- package/dist/tools/users/index.js +5 -0
- package/dist/transports/http.d.ts +17 -0
- package/dist/transports/http.js +203 -0
- package/dist/transports/index.d.ts +4 -0
- package/dist/transports/index.js +4 -0
- package/dist/types/common.d.ts +32 -0
- package/dist/types/common.js +11 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.js +11 -0
- package/dist/types/schemas/accounting.d.ts +225 -0
- package/dist/types/schemas/accounting.js +96 -0
- package/dist/types/schemas/banking.d.ts +207 -0
- package/dist/types/schemas/banking.js +86 -0
- package/dist/types/schemas/company.d.ts +44 -0
- package/dist/types/schemas/company.js +23 -0
- package/dist/types/schemas/contacts.d.ts +104 -0
- package/dist/types/schemas/contacts.js +42 -0
- package/dist/types/schemas/deliveries.d.ts +40 -0
- package/dist/types/schemas/deliveries.js +22 -0
- package/dist/types/schemas/files.d.ts +152 -0
- package/dist/types/schemas/files.js +64 -0
- package/dist/types/schemas/index.d.ts +24 -0
- package/dist/types/schemas/index.js +44 -0
- package/dist/types/schemas/invoices.d.ts +594 -0
- package/dist/types/schemas/invoices.js +109 -0
- package/dist/types/schemas/items.d.ts +153 -0
- package/dist/types/schemas/items.js +43 -0
- package/dist/types/schemas/misc.d.ts +64 -0
- package/dist/types/schemas/misc.js +36 -0
- package/dist/types/schemas/orders.d.ts +657 -0
- package/dist/types/schemas/orders.js +101 -0
- package/dist/types/schemas/payments.d.ts +46 -0
- package/dist/types/schemas/payments.js +24 -0
- package/dist/types/schemas/payroll.d.ts +146 -0
- package/dist/types/schemas/payroll.js +65 -0
- package/dist/types/schemas/projects.d.ts +268 -0
- package/dist/types/schemas/projects.js +102 -0
- package/dist/types/schemas/purchase.d.ts +228 -0
- package/dist/types/schemas/purchase.js +114 -0
- package/dist/types/schemas/quotes.d.ts +102 -0
- package/dist/types/schemas/quotes.js +49 -0
- package/dist/types/schemas/reference.d.ts +240 -0
- package/dist/types/schemas/reference.js +99 -0
- package/dist/types/schemas/reminders.d.ts +76 -0
- package/dist/types/schemas/reminders.js +38 -0
- package/dist/types/schemas/reports.d.ts +69 -0
- package/dist/types/schemas/reports.js +36 -0
- package/dist/types/schemas/timetracking.d.ts +150 -0
- package/dist/types/schemas/timetracking.js +68 -0
- package/dist/types/schemas/users.d.ts +51 -0
- package/dist/types/schemas/users.js +27 -0
- package/dist/ui/contact-card/mcp-app.d.ts +1 -0
- package/dist/ui/contact-card/mcp-app.js +108 -0
- package/dist/ui/dashboard/mcp-app.d.ts +1 -0
- package/dist/ui/dashboard/mcp-app.js +81 -0
- package/dist/ui/invoice-preview/mcp-app.d.ts +1 -0
- package/dist/ui/invoice-preview/mcp-app.js +96 -0
- package/dist/ui-resources.d.ts +17 -0
- package/dist/ui-resources.js +124 -0
- package/dist/vite.config.d.ts +2 -0
- package/dist/vite.config.js +46 -0
- package/package.json +78 -0
|
@@ -0,0 +1,1045 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bexio API Client.
|
|
3
|
+
* Handles all HTTP communication with the Bexio API.
|
|
4
|
+
* Uses logger for all output (no console.log).
|
|
5
|
+
*/
|
|
6
|
+
import axios from "axios";
|
|
7
|
+
import { logger } from "./logger.js";
|
|
8
|
+
import { McpError } from "./shared/errors.js";
|
|
9
|
+
export class BexioClient {
|
|
10
|
+
client;
|
|
11
|
+
config;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.client = axios.create({
|
|
15
|
+
baseURL: config.baseUrl,
|
|
16
|
+
headers: {
|
|
17
|
+
Authorization: `Bearer ${config.apiToken}`,
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
Accept: "application/json",
|
|
20
|
+
},
|
|
21
|
+
timeout: 30000,
|
|
22
|
+
});
|
|
23
|
+
// Add response interceptor for error handling
|
|
24
|
+
this.client.interceptors.response.use((response) => response, (error) => {
|
|
25
|
+
if (error.response) {
|
|
26
|
+
const status = error.response.status;
|
|
27
|
+
const message = error.response.data?.message || error.response.statusText;
|
|
28
|
+
throw McpError.bexioApi(message, status, {
|
|
29
|
+
url: error.config?.url,
|
|
30
|
+
method: error.config?.method,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else if (error.request) {
|
|
34
|
+
throw McpError.bexioApi("No response received from server", undefined, {
|
|
35
|
+
error: "NETWORK_ERROR",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
throw McpError.internal(error.message);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async makeRequest(method, endpoint, params, data) {
|
|
44
|
+
logger.debug(`${method} ${endpoint}`, { params, hasData: !!data });
|
|
45
|
+
const response = await this.client.request({
|
|
46
|
+
method,
|
|
47
|
+
url: endpoint,
|
|
48
|
+
params,
|
|
49
|
+
data,
|
|
50
|
+
});
|
|
51
|
+
return response.data;
|
|
52
|
+
}
|
|
53
|
+
// ===== CONTACT GROUPS =====
|
|
54
|
+
async listContactGroups(params = {}) {
|
|
55
|
+
return this.makeRequest("GET", "/contact_group", params);
|
|
56
|
+
}
|
|
57
|
+
async getContactGroup(groupId) {
|
|
58
|
+
return this.makeRequest("GET", `/contact_group/${groupId}`);
|
|
59
|
+
}
|
|
60
|
+
async createContactGroup(data) {
|
|
61
|
+
return this.makeRequest("POST", "/contact_group", undefined, data);
|
|
62
|
+
}
|
|
63
|
+
async deleteContactGroup(groupId) {
|
|
64
|
+
return this.makeRequest("DELETE", `/contact_group/${groupId}`);
|
|
65
|
+
}
|
|
66
|
+
// ===== CONTACT SECTORS =====
|
|
67
|
+
async listContactSectors(params = {}) {
|
|
68
|
+
return this.makeRequest("GET", "/contact_sector", params);
|
|
69
|
+
}
|
|
70
|
+
async getContactSector(sectorId) {
|
|
71
|
+
return this.makeRequest("GET", `/contact_sector/${sectorId}`);
|
|
72
|
+
}
|
|
73
|
+
async createContactSector(data) {
|
|
74
|
+
return this.makeRequest("POST", "/contact_sector", undefined, data);
|
|
75
|
+
}
|
|
76
|
+
// ===== SALUTATIONS =====
|
|
77
|
+
async listSalutations(params = {}) {
|
|
78
|
+
return this.makeRequest("GET", "/salutation", params);
|
|
79
|
+
}
|
|
80
|
+
async getSalutation(salutationId) {
|
|
81
|
+
return this.makeRequest("GET", `/salutation/${salutationId}`);
|
|
82
|
+
}
|
|
83
|
+
async createSalutation(data) {
|
|
84
|
+
return this.makeRequest("POST", "/salutation", undefined, data);
|
|
85
|
+
}
|
|
86
|
+
async deleteSalutation(salutationId) {
|
|
87
|
+
return this.makeRequest("DELETE", `/salutation/${salutationId}`);
|
|
88
|
+
}
|
|
89
|
+
// ===== TITLES =====
|
|
90
|
+
async listTitles(params = {}) {
|
|
91
|
+
return this.makeRequest("GET", "/title", params);
|
|
92
|
+
}
|
|
93
|
+
async getTitle(titleId) {
|
|
94
|
+
return this.makeRequest("GET", `/title/${titleId}`);
|
|
95
|
+
}
|
|
96
|
+
async createTitle(data) {
|
|
97
|
+
return this.makeRequest("POST", "/title", undefined, data);
|
|
98
|
+
}
|
|
99
|
+
async deleteTitle(titleId) {
|
|
100
|
+
return this.makeRequest("DELETE", `/title/${titleId}`);
|
|
101
|
+
}
|
|
102
|
+
// ===== COUNTRIES =====
|
|
103
|
+
async listCountries(params = {}) {
|
|
104
|
+
return this.makeRequest("GET", "/country", params);
|
|
105
|
+
}
|
|
106
|
+
async getCountry(countryId) {
|
|
107
|
+
return this.makeRequest("GET", `/country/${countryId}`);
|
|
108
|
+
}
|
|
109
|
+
async createCountry(data) {
|
|
110
|
+
return this.makeRequest("POST", "/country", undefined, data);
|
|
111
|
+
}
|
|
112
|
+
async deleteCountry(countryId) {
|
|
113
|
+
return this.makeRequest("DELETE", `/country/${countryId}`);
|
|
114
|
+
}
|
|
115
|
+
// ===== LANGUAGES =====
|
|
116
|
+
async listLanguages(params = {}) {
|
|
117
|
+
return this.makeRequest("GET", "/language", params);
|
|
118
|
+
}
|
|
119
|
+
async getLanguage(languageId) {
|
|
120
|
+
return this.makeRequest("GET", `/language/${languageId}`);
|
|
121
|
+
}
|
|
122
|
+
async createLanguage(data) {
|
|
123
|
+
return this.makeRequest("POST", "/language", undefined, data);
|
|
124
|
+
}
|
|
125
|
+
// ===== UNITS =====
|
|
126
|
+
async listUnits(params = {}) {
|
|
127
|
+
return this.makeRequest("GET", "/unit", params);
|
|
128
|
+
}
|
|
129
|
+
async getUnit(unitId) {
|
|
130
|
+
return this.makeRequest("GET", `/unit/${unitId}`);
|
|
131
|
+
}
|
|
132
|
+
async createUnit(data) {
|
|
133
|
+
return this.makeRequest("POST", "/unit", undefined, data);
|
|
134
|
+
}
|
|
135
|
+
async deleteUnit(unitId) {
|
|
136
|
+
return this.makeRequest("DELETE", `/unit/${unitId}`);
|
|
137
|
+
}
|
|
138
|
+
// ===== COMPANY PROFILE =====
|
|
139
|
+
async getCompanyProfile() {
|
|
140
|
+
return this.makeRequest("GET", "/company_profile");
|
|
141
|
+
}
|
|
142
|
+
async updateCompanyProfile(data) {
|
|
143
|
+
return this.makeRequest("POST", "/company_profile", undefined, data);
|
|
144
|
+
}
|
|
145
|
+
// ===== PERMISSIONS =====
|
|
146
|
+
async listPermissions() {
|
|
147
|
+
return this.makeRequest("GET", "/permission");
|
|
148
|
+
}
|
|
149
|
+
// ===== PAYMENT TYPES =====
|
|
150
|
+
async listPaymentTypes(params = {}) {
|
|
151
|
+
return this.makeRequest("GET", "/payment_type", params);
|
|
152
|
+
}
|
|
153
|
+
async getPaymentType(paymentTypeId) {
|
|
154
|
+
return this.makeRequest("GET", `/payment_type/${paymentTypeId}`);
|
|
155
|
+
}
|
|
156
|
+
async createPaymentType(data) {
|
|
157
|
+
return this.makeRequest("POST", "/payment_type", undefined, data);
|
|
158
|
+
}
|
|
159
|
+
// ===== BANK ACCOUNTS (Read-Only) =====
|
|
160
|
+
async listBankAccounts(params = {}) {
|
|
161
|
+
return this.makeRequest("GET", "/bank_account", params);
|
|
162
|
+
}
|
|
163
|
+
async getBankAccount(accountId) {
|
|
164
|
+
return this.makeRequest("GET", `/bank_account/${accountId}`);
|
|
165
|
+
}
|
|
166
|
+
// ===== CURRENCIES =====
|
|
167
|
+
async listCurrencies(params = {}) {
|
|
168
|
+
return this.makeRequest("GET", "/currency", params);
|
|
169
|
+
}
|
|
170
|
+
async getCurrency(currencyId) {
|
|
171
|
+
return this.makeRequest("GET", `/currency/${currencyId}`);
|
|
172
|
+
}
|
|
173
|
+
async createCurrency(data) {
|
|
174
|
+
return this.makeRequest("POST", "/currency", undefined, data);
|
|
175
|
+
}
|
|
176
|
+
async updateCurrency(currencyId, data) {
|
|
177
|
+
return this.makeRequest("PATCH", `/currency/${currencyId}`, undefined, data);
|
|
178
|
+
}
|
|
179
|
+
async deleteCurrency(currencyId) {
|
|
180
|
+
return this.makeRequest("DELETE", `/currency/${currencyId}`);
|
|
181
|
+
}
|
|
182
|
+
// ===== IBAN PAYMENTS (Swiss ISO 20022) =====
|
|
183
|
+
async createIbanPayment(data) {
|
|
184
|
+
return this.makeRequest("POST", "/iban_payment", undefined, data);
|
|
185
|
+
}
|
|
186
|
+
async getIbanPayment(paymentId) {
|
|
187
|
+
return this.makeRequest("GET", `/iban_payment/${paymentId}`);
|
|
188
|
+
}
|
|
189
|
+
async updateIbanPayment(paymentId, data) {
|
|
190
|
+
return this.makeRequest("PATCH", `/iban_payment/${paymentId}`, undefined, data);
|
|
191
|
+
}
|
|
192
|
+
// ===== QR PAYMENTS (Swiss QR-invoice standard) =====
|
|
193
|
+
async createQrPayment(data) {
|
|
194
|
+
return this.makeRequest("POST", "/qr_payment", undefined, data);
|
|
195
|
+
}
|
|
196
|
+
async getQrPayment(paymentId) {
|
|
197
|
+
return this.makeRequest("GET", `/qr_payment/${paymentId}`);
|
|
198
|
+
}
|
|
199
|
+
async updateQrPayment(paymentId, data) {
|
|
200
|
+
return this.makeRequest("PATCH", `/qr_payment/${paymentId}`, undefined, data);
|
|
201
|
+
}
|
|
202
|
+
// ===== ORDERS =====
|
|
203
|
+
async listOrders(params = {}) {
|
|
204
|
+
return this.makeRequest("GET", "/kb_order", params);
|
|
205
|
+
}
|
|
206
|
+
async getOrder(orderId) {
|
|
207
|
+
return this.makeRequest("GET", `/kb_order/${orderId}`);
|
|
208
|
+
}
|
|
209
|
+
async createOrder(orderData) {
|
|
210
|
+
return this.makeRequest("POST", "/kb_order", undefined, orderData);
|
|
211
|
+
}
|
|
212
|
+
async searchOrders(searchParams) {
|
|
213
|
+
return this.makeRequest("POST", "/kb_order/search", undefined, searchParams);
|
|
214
|
+
}
|
|
215
|
+
async searchOrdersByContactId(contactId) {
|
|
216
|
+
const searchParams = [
|
|
217
|
+
{ field: "contact_id", operator: "=", value: contactId.toString() },
|
|
218
|
+
];
|
|
219
|
+
return this.makeRequest("POST", "/kb_order/search", undefined, searchParams);
|
|
220
|
+
}
|
|
221
|
+
async createDeliveryFromOrder(orderId) {
|
|
222
|
+
return this.makeRequest("POST", `/kb_order/${orderId}/create_delivery`);
|
|
223
|
+
}
|
|
224
|
+
async createInvoiceFromOrder(orderId) {
|
|
225
|
+
return this.makeRequest("POST", `/kb_order/${orderId}/create_invoice`);
|
|
226
|
+
}
|
|
227
|
+
// ===== CONTACTS =====
|
|
228
|
+
async listContacts(params = {}) {
|
|
229
|
+
const searchParams = {
|
|
230
|
+
limit: params.limit ?? 50,
|
|
231
|
+
offset: params.offset ?? 0,
|
|
232
|
+
};
|
|
233
|
+
if (params.search_term) {
|
|
234
|
+
searchParams["search"] = params.search_term;
|
|
235
|
+
}
|
|
236
|
+
if (params.contact_type_id) {
|
|
237
|
+
searchParams["contact_type_id"] = params.contact_type_id;
|
|
238
|
+
}
|
|
239
|
+
return this.makeRequest("GET", "/contact", searchParams);
|
|
240
|
+
}
|
|
241
|
+
async getContact(contactId) {
|
|
242
|
+
return this.makeRequest("GET", `/contact/${contactId}`);
|
|
243
|
+
}
|
|
244
|
+
async searchContacts(query, limit = 50) {
|
|
245
|
+
const searchCriteria = [
|
|
246
|
+
{ field: "name_1", value: query, criteria: "like" },
|
|
247
|
+
];
|
|
248
|
+
return this.advancedSearchContacts(searchCriteria, limit);
|
|
249
|
+
}
|
|
250
|
+
async advancedSearchContacts(searchCriteria, limit = 50) {
|
|
251
|
+
const params = { limit };
|
|
252
|
+
return this.makeRequest("POST", "/contact/search", params, searchCriteria);
|
|
253
|
+
}
|
|
254
|
+
async findContactByNumber(contactNumber) {
|
|
255
|
+
const searchCriteria = [
|
|
256
|
+
{ field: "nr", value: contactNumber, criteria: "=" },
|
|
257
|
+
];
|
|
258
|
+
const contacts = await this.advancedSearchContacts(searchCriteria, 1);
|
|
259
|
+
if (Array.isArray(contacts) && contacts.length > 0) {
|
|
260
|
+
return contacts[0];
|
|
261
|
+
}
|
|
262
|
+
throw McpError.notFound("Contact", contactNumber);
|
|
263
|
+
}
|
|
264
|
+
async findContactByName(name) {
|
|
265
|
+
const searchCriteria = [
|
|
266
|
+
{ field: "name_1", value: name, criteria: "like" },
|
|
267
|
+
];
|
|
268
|
+
return this.advancedSearchContacts(searchCriteria, 100);
|
|
269
|
+
}
|
|
270
|
+
async updateContact(contactId, contactData) {
|
|
271
|
+
return this.makeRequest("POST", `/contact/${contactId}`, undefined, contactData);
|
|
272
|
+
}
|
|
273
|
+
// ===== QUOTES =====
|
|
274
|
+
async createQuote(quoteData) {
|
|
275
|
+
return this.makeRequest("POST", "/kb_offer", undefined, quoteData);
|
|
276
|
+
}
|
|
277
|
+
async listQuotes(params = {}) {
|
|
278
|
+
return this.makeRequest("GET", "/kb_offer", params);
|
|
279
|
+
}
|
|
280
|
+
async getQuote(quoteId) {
|
|
281
|
+
return this.makeRequest("GET", `/kb_offer/${quoteId}`);
|
|
282
|
+
}
|
|
283
|
+
async searchQuotes(searchParams) {
|
|
284
|
+
return this.makeRequest("POST", "/kb_offer/search", undefined, searchParams);
|
|
285
|
+
}
|
|
286
|
+
async searchQuotesByContactId(contactId) {
|
|
287
|
+
const searchParams = [
|
|
288
|
+
{ field: "contact_id", operator: "=", value: contactId.toString() },
|
|
289
|
+
];
|
|
290
|
+
return this.makeRequest("POST", "/kb_offer/search", undefined, searchParams);
|
|
291
|
+
}
|
|
292
|
+
async issueQuote(quoteId) {
|
|
293
|
+
return this.makeRequest("POST", `/kb_offer/${quoteId}/issue`);
|
|
294
|
+
}
|
|
295
|
+
async acceptQuote(quoteId) {
|
|
296
|
+
return this.makeRequest("POST", `/kb_offer/${quoteId}/accept`);
|
|
297
|
+
}
|
|
298
|
+
async declineQuote(quoteId) {
|
|
299
|
+
return this.makeRequest("POST", `/kb_offer/${quoteId}/decline`);
|
|
300
|
+
}
|
|
301
|
+
async sendQuote(quoteId) {
|
|
302
|
+
return this.makeRequest("POST", `/kb_offer/${quoteId}/send`);
|
|
303
|
+
}
|
|
304
|
+
async createOrderFromQuote(quoteId) {
|
|
305
|
+
return this.makeRequest("POST", `/kb_offer/${quoteId}/create_order`);
|
|
306
|
+
}
|
|
307
|
+
async createInvoiceFromQuote(quoteId) {
|
|
308
|
+
return this.makeRequest("POST", `/kb_offer/${quoteId}/create_invoice`);
|
|
309
|
+
}
|
|
310
|
+
// ===== INVOICES =====
|
|
311
|
+
async listInvoices(params = {}) {
|
|
312
|
+
return this.makeRequest("GET", "/kb_invoice", params);
|
|
313
|
+
}
|
|
314
|
+
async getInvoice(invoiceId) {
|
|
315
|
+
return this.makeRequest("GET", `/kb_invoice/${invoiceId}`);
|
|
316
|
+
}
|
|
317
|
+
async createInvoice(invoiceData) {
|
|
318
|
+
// Set current date if not provided
|
|
319
|
+
if (!invoiceData.is_valid_from) {
|
|
320
|
+
invoiceData.is_valid_from = new Date().toISOString().split("T")[0];
|
|
321
|
+
}
|
|
322
|
+
return this.makeRequest("POST", "/kb_invoice", undefined, invoiceData);
|
|
323
|
+
}
|
|
324
|
+
async listAllInvoices(chunkSize = 100) {
|
|
325
|
+
if (chunkSize <= 0) {
|
|
326
|
+
throw McpError.validation("chunk_size must be positive");
|
|
327
|
+
}
|
|
328
|
+
const invoices = [];
|
|
329
|
+
let offset = 0;
|
|
330
|
+
while (offset < 10000) {
|
|
331
|
+
const batch = await this.listInvoices({ limit: chunkSize, offset });
|
|
332
|
+
if (!Array.isArray(batch) || batch.length === 0) {
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
invoices.push(...batch);
|
|
336
|
+
if (batch.length < chunkSize) {
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
offset += chunkSize;
|
|
340
|
+
}
|
|
341
|
+
return invoices;
|
|
342
|
+
}
|
|
343
|
+
async searchInvoices(params) {
|
|
344
|
+
const searchFilters = [];
|
|
345
|
+
if (params.filters) {
|
|
346
|
+
if (!Array.isArray(params.filters)) {
|
|
347
|
+
throw McpError.validation("filters must be a list of search expressions");
|
|
348
|
+
}
|
|
349
|
+
searchFilters.push(...params.filters);
|
|
350
|
+
}
|
|
351
|
+
if (params.query !== undefined) {
|
|
352
|
+
const op = params.operator?.toUpperCase() ?? "LIKE";
|
|
353
|
+
let value = params.query;
|
|
354
|
+
if (op === "LIKE" && !value.includes("%")) {
|
|
355
|
+
value = `%${params.query}%`;
|
|
356
|
+
}
|
|
357
|
+
searchFilters.push({
|
|
358
|
+
field: params.field ?? "title",
|
|
359
|
+
operator: op,
|
|
360
|
+
value: value,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (searchFilters.length === 0) {
|
|
364
|
+
throw McpError.validation("Either query or filters must be provided");
|
|
365
|
+
}
|
|
366
|
+
const requestParams = params.limit ? { limit: params.limit } : undefined;
|
|
367
|
+
return this.makeRequest("POST", "/kb_invoice/search", requestParams, searchFilters);
|
|
368
|
+
}
|
|
369
|
+
async issueInvoice(invoiceId) {
|
|
370
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/issue`);
|
|
371
|
+
}
|
|
372
|
+
async cancelInvoice(invoiceId) {
|
|
373
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/cancel`);
|
|
374
|
+
}
|
|
375
|
+
async markInvoiceAsSent(invoiceId) {
|
|
376
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/mark_as_sent`);
|
|
377
|
+
}
|
|
378
|
+
async sendInvoice(invoiceId) {
|
|
379
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/send`);
|
|
380
|
+
}
|
|
381
|
+
async copyInvoice(invoiceId) {
|
|
382
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/copy`);
|
|
383
|
+
}
|
|
384
|
+
// ===== TAXES (3.0 API) =====
|
|
385
|
+
async listTaxes(params = {}) {
|
|
386
|
+
const response = await axios.get("https://api.bexio.com/3.0/taxes", {
|
|
387
|
+
headers: {
|
|
388
|
+
Authorization: `Bearer ${this.config.apiToken}`,
|
|
389
|
+
"Content-Type": "application/json",
|
|
390
|
+
Accept: "application/json",
|
|
391
|
+
},
|
|
392
|
+
params,
|
|
393
|
+
});
|
|
394
|
+
return response.data;
|
|
395
|
+
}
|
|
396
|
+
async getTax(taxId) {
|
|
397
|
+
const response = await axios.get(`https://api.bexio.com/3.0/taxes/${taxId}`, {
|
|
398
|
+
headers: {
|
|
399
|
+
Authorization: `Bearer ${this.config.apiToken}`,
|
|
400
|
+
"Content-Type": "application/json",
|
|
401
|
+
Accept: "application/json",
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
return response.data;
|
|
405
|
+
}
|
|
406
|
+
// ===== ITEMS (Articles) =====
|
|
407
|
+
async listItems(params = {}) {
|
|
408
|
+
return this.makeRequest("GET", "/article", params);
|
|
409
|
+
}
|
|
410
|
+
async getItem(itemId) {
|
|
411
|
+
return this.makeRequest("GET", `/article/${itemId}`);
|
|
412
|
+
}
|
|
413
|
+
async createItem(itemData) {
|
|
414
|
+
return this.makeRequest("POST", "/article", undefined, itemData);
|
|
415
|
+
}
|
|
416
|
+
// ===== DELIVERIES =====
|
|
417
|
+
async listDeliveries(params = {}) {
|
|
418
|
+
return this.makeRequest("GET", "/kb_delivery", params);
|
|
419
|
+
}
|
|
420
|
+
async getDelivery(deliveryId) {
|
|
421
|
+
return this.makeRequest("GET", `/kb_delivery/${deliveryId}`);
|
|
422
|
+
}
|
|
423
|
+
async issueDelivery(deliveryId) {
|
|
424
|
+
return this.makeRequest("POST", `/kb_delivery/${deliveryId}/issue`);
|
|
425
|
+
}
|
|
426
|
+
async searchDeliveries(searchParams) {
|
|
427
|
+
return this.makeRequest("POST", "/kb_delivery/search", undefined, searchParams);
|
|
428
|
+
}
|
|
429
|
+
// ===== PAYMENTS =====
|
|
430
|
+
async listPayments(invoiceId) {
|
|
431
|
+
return this.makeRequest("GET", `/kb_invoice/${invoiceId}/payment`);
|
|
432
|
+
}
|
|
433
|
+
async createPayment(invoiceId, paymentData) {
|
|
434
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/payment`, undefined, paymentData);
|
|
435
|
+
}
|
|
436
|
+
async getPayment(invoiceId, paymentId) {
|
|
437
|
+
return this.makeRequest("GET", `/kb_invoice/${invoiceId}/payment/${paymentId}`);
|
|
438
|
+
}
|
|
439
|
+
async deletePayment(invoiceId, paymentId) {
|
|
440
|
+
return this.makeRequest("DELETE", `/kb_invoice/${invoiceId}/payment/${paymentId}`);
|
|
441
|
+
}
|
|
442
|
+
// ===== REMINDERS =====
|
|
443
|
+
async listReminders(invoiceId) {
|
|
444
|
+
return this.makeRequest("GET", `/kb_invoice/${invoiceId}/reminder`);
|
|
445
|
+
}
|
|
446
|
+
async createReminder(invoiceId, reminderData) {
|
|
447
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/reminder`, undefined, reminderData);
|
|
448
|
+
}
|
|
449
|
+
async getReminder(invoiceId, reminderId) {
|
|
450
|
+
return this.makeRequest("GET", `/kb_invoice/${invoiceId}/reminder/${reminderId}`);
|
|
451
|
+
}
|
|
452
|
+
async deleteReminder(invoiceId, reminderId) {
|
|
453
|
+
return this.makeRequest("DELETE", `/kb_invoice/${invoiceId}/reminder/${reminderId}`);
|
|
454
|
+
}
|
|
455
|
+
async markReminderAsSent(invoiceId, reminderId) {
|
|
456
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/reminder/${reminderId}/mark_as_sent`);
|
|
457
|
+
}
|
|
458
|
+
async sendReminder(invoiceId, reminderId) {
|
|
459
|
+
return this.makeRequest("POST", `/kb_invoice/${invoiceId}/reminder/${reminderId}/send`);
|
|
460
|
+
}
|
|
461
|
+
// ===== CONTACT RELATIONS =====
|
|
462
|
+
async listContactRelations() {
|
|
463
|
+
return this.makeRequest("GET", "/contact_relation");
|
|
464
|
+
}
|
|
465
|
+
async createContactRelation(relationData) {
|
|
466
|
+
return this.makeRequest("POST", "/contact_relation", undefined, relationData);
|
|
467
|
+
}
|
|
468
|
+
async getContactRelation(relationId) {
|
|
469
|
+
return this.makeRequest("GET", `/contact_relation/${relationId}`);
|
|
470
|
+
}
|
|
471
|
+
async updateContactRelation(relationId, relationData) {
|
|
472
|
+
return this.makeRequest("POST", `/contact_relation/${relationId}`, undefined, relationData);
|
|
473
|
+
}
|
|
474
|
+
async deleteContactRelation(relationId) {
|
|
475
|
+
return this.makeRequest("DELETE", `/contact_relation/${relationId}`);
|
|
476
|
+
}
|
|
477
|
+
async searchContactRelations(searchParams) {
|
|
478
|
+
return this.makeRequest("POST", "/contact_relation/search", undefined, searchParams);
|
|
479
|
+
}
|
|
480
|
+
// ===== USERS =====
|
|
481
|
+
async getCurrentUser() {
|
|
482
|
+
return this.makeRequest("GET", "/user/me");
|
|
483
|
+
}
|
|
484
|
+
async listFictionalUsers(params = {}) {
|
|
485
|
+
return this.makeRequest("GET", "/fictional_user", params);
|
|
486
|
+
}
|
|
487
|
+
async getFictionalUser(userId) {
|
|
488
|
+
return this.makeRequest("GET", `/fictional_user/${userId}`);
|
|
489
|
+
}
|
|
490
|
+
async createFictionalUser(userData) {
|
|
491
|
+
return this.makeRequest("POST", "/fictional_user", undefined, userData);
|
|
492
|
+
}
|
|
493
|
+
async updateFictionalUser(userId, userData) {
|
|
494
|
+
return this.makeRequest("POST", `/fictional_user/${userId}`, undefined, userData);
|
|
495
|
+
}
|
|
496
|
+
async deleteFictionalUser(userId) {
|
|
497
|
+
return this.makeRequest("DELETE", `/fictional_user/${userId}`);
|
|
498
|
+
}
|
|
499
|
+
// ===== COMMENTS =====
|
|
500
|
+
async listComments() {
|
|
501
|
+
return this.makeRequest("GET", "/comment");
|
|
502
|
+
}
|
|
503
|
+
async getComment(commentId) {
|
|
504
|
+
return this.makeRequest("GET", `/comment/${commentId}`);
|
|
505
|
+
}
|
|
506
|
+
async createComment(commentData) {
|
|
507
|
+
return this.makeRequest("POST", "/comment", undefined, commentData);
|
|
508
|
+
}
|
|
509
|
+
// ===== SEARCH REMINDERS =====
|
|
510
|
+
async searchReminders(searchParams) {
|
|
511
|
+
// Search across all invoices to find reminders matching criteria
|
|
512
|
+
// This is a computed operation - get all recent invoices and their reminders
|
|
513
|
+
const invoices = await this.listAllInvoices(100);
|
|
514
|
+
const allReminders = [];
|
|
515
|
+
for (const invoice of invoices.slice(0, 50)) {
|
|
516
|
+
const invoiceId = invoice.id;
|
|
517
|
+
if (invoiceId) {
|
|
518
|
+
try {
|
|
519
|
+
const reminders = await this.listReminders(invoiceId);
|
|
520
|
+
allReminders.push(...reminders.map((r) => ({
|
|
521
|
+
...r,
|
|
522
|
+
invoice_id: invoiceId,
|
|
523
|
+
})));
|
|
524
|
+
}
|
|
525
|
+
catch {
|
|
526
|
+
// Invoice may not have reminders, skip
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return allReminders;
|
|
531
|
+
}
|
|
532
|
+
async getRemindersSentThisWeek() {
|
|
533
|
+
// Get reminders sent this week
|
|
534
|
+
const now = new Date();
|
|
535
|
+
const startOfWeek = new Date(now);
|
|
536
|
+
startOfWeek.setDate(now.getDate() - now.getDay());
|
|
537
|
+
startOfWeek.setHours(0, 0, 0, 0);
|
|
538
|
+
const allReminders = await this.searchReminders({});
|
|
539
|
+
return allReminders.filter((r) => {
|
|
540
|
+
const sentDate = r.sent_date;
|
|
541
|
+
if (!sentDate)
|
|
542
|
+
return false;
|
|
543
|
+
const date = new Date(sentDate);
|
|
544
|
+
return date >= startOfWeek;
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
// ===== REPORTS (Computed from invoice data) =====
|
|
548
|
+
async getRevenueReport(startDate, endDate, groupBy) {
|
|
549
|
+
// Compute revenue from paid invoices in date range
|
|
550
|
+
const invoices = await this.listAllInvoices(100);
|
|
551
|
+
const filteredInvoices = invoices.filter((inv) => {
|
|
552
|
+
const invoice = inv;
|
|
553
|
+
const invDate = invoice.is_valid_from;
|
|
554
|
+
// Status 9 = paid
|
|
555
|
+
const isPaid = invoice.kb_item_status_id === 9;
|
|
556
|
+
if (!invDate || !isPaid)
|
|
557
|
+
return false;
|
|
558
|
+
return invDate >= startDate && invDate <= endDate;
|
|
559
|
+
});
|
|
560
|
+
const totalRevenue = filteredInvoices.reduce((sum, inv) => {
|
|
561
|
+
const total = inv.total ?? 0;
|
|
562
|
+
return sum + total;
|
|
563
|
+
}, 0);
|
|
564
|
+
return {
|
|
565
|
+
start_date: startDate,
|
|
566
|
+
end_date: endDate,
|
|
567
|
+
total_revenue: totalRevenue,
|
|
568
|
+
invoice_count: filteredInvoices.length,
|
|
569
|
+
group_by: groupBy || null,
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
async getCustomerRevenueReport(startDate, endDate, limit = 10) {
|
|
573
|
+
const invoices = await this.listAllInvoices(100);
|
|
574
|
+
const customerRevenue = {};
|
|
575
|
+
invoices.forEach((inv) => {
|
|
576
|
+
const invoice = inv;
|
|
577
|
+
if (invoice.contact_id &&
|
|
578
|
+
invoice.is_valid_from &&
|
|
579
|
+
invoice.is_valid_from >= startDate &&
|
|
580
|
+
invoice.is_valid_from <= endDate &&
|
|
581
|
+
invoice.kb_item_status_id === 9) {
|
|
582
|
+
if (!customerRevenue[invoice.contact_id]) {
|
|
583
|
+
customerRevenue[invoice.contact_id] = {
|
|
584
|
+
contact_id: invoice.contact_id,
|
|
585
|
+
total: 0,
|
|
586
|
+
count: 0,
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
customerRevenue[invoice.contact_id].total += invoice.total ?? 0;
|
|
590
|
+
customerRevenue[invoice.contact_id].count += 1;
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
return Object.values(customerRevenue)
|
|
594
|
+
.sort((a, b) => b.total - a.total)
|
|
595
|
+
.slice(0, limit);
|
|
596
|
+
}
|
|
597
|
+
async getInvoiceStatusReport(startDate, endDate) {
|
|
598
|
+
const invoices = await this.listAllInvoices(100);
|
|
599
|
+
const statusCounts = {};
|
|
600
|
+
invoices.forEach((inv) => {
|
|
601
|
+
const invoice = inv;
|
|
602
|
+
if (invoice.is_valid_from &&
|
|
603
|
+
invoice.is_valid_from >= startDate &&
|
|
604
|
+
invoice.is_valid_from <= endDate &&
|
|
605
|
+
invoice.kb_item_status_id) {
|
|
606
|
+
statusCounts[invoice.kb_item_status_id] =
|
|
607
|
+
(statusCounts[invoice.kb_item_status_id] || 0) + 1;
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
return {
|
|
611
|
+
start_date: startDate,
|
|
612
|
+
end_date: endDate,
|
|
613
|
+
status_counts: statusCounts,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
async getOverdueInvoicesReport() {
|
|
617
|
+
return this.getOverdueInvoices();
|
|
618
|
+
}
|
|
619
|
+
async getMonthlyRevenueReport(year, month) {
|
|
620
|
+
const startDate = `${year}-${String(month).padStart(2, "0")}-01`;
|
|
621
|
+
const lastDay = new Date(year, month, 0).getDate();
|
|
622
|
+
const endDate = `${year}-${String(month).padStart(2, "0")}-${lastDay}`;
|
|
623
|
+
return this.getRevenueReport(startDate, endDate);
|
|
624
|
+
}
|
|
625
|
+
async getTopCustomersByRevenue(limit = 10, startDate, endDate) {
|
|
626
|
+
const start = startDate || "2000-01-01";
|
|
627
|
+
const end = endDate || new Date().toISOString().split("T")[0];
|
|
628
|
+
return this.getCustomerRevenueReport(start, end, limit);
|
|
629
|
+
}
|
|
630
|
+
// ===== BUSINESS LOGIC =====
|
|
631
|
+
async getOpenInvoices() {
|
|
632
|
+
// Status 7 = Draft/Open, Status 8 = Sent/Pending
|
|
633
|
+
const invoices = await this.listAllInvoices(100);
|
|
634
|
+
return invoices.filter((inv) => {
|
|
635
|
+
const statusId = inv.kb_item_status_id;
|
|
636
|
+
return statusId === 7 || statusId === 8;
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
async getOverdueInvoices() {
|
|
640
|
+
const today = new Date().toISOString().split("T")[0];
|
|
641
|
+
const invoices = await this.listAllInvoices(100);
|
|
642
|
+
return invoices.filter((inv) => {
|
|
643
|
+
const invoice = inv;
|
|
644
|
+
// Status 8 = Sent but not paid, and due date passed
|
|
645
|
+
return (invoice.kb_item_status_id === 8 &&
|
|
646
|
+
invoice.is_valid_until &&
|
|
647
|
+
invoice.is_valid_until < today);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
async getTasksDueThisWeek() {
|
|
651
|
+
const now = new Date();
|
|
652
|
+
const endOfWeek = new Date(now);
|
|
653
|
+
endOfWeek.setDate(now.getDate() + (6 - now.getDay()));
|
|
654
|
+
const today = now.toISOString().split("T")[0];
|
|
655
|
+
const weekEnd = endOfWeek.toISOString().split("T")[0];
|
|
656
|
+
const invoices = await this.listAllInvoices(100);
|
|
657
|
+
return invoices.filter((inv) => {
|
|
658
|
+
const invoice = inv;
|
|
659
|
+
// Open or sent invoices with due date this week
|
|
660
|
+
const isOpen = invoice.kb_item_status_id === 7 || invoice.kb_item_status_id === 8;
|
|
661
|
+
const dueDate = invoice.is_valid_until;
|
|
662
|
+
return isOpen && dueDate && dueDate >= today && dueDate <= weekEnd;
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
// ===== STATIC DATA =====
|
|
666
|
+
async listInvoiceStatuses() {
|
|
667
|
+
return [
|
|
668
|
+
{
|
|
669
|
+
id: 7,
|
|
670
|
+
name: "Entwurf/Offen",
|
|
671
|
+
english_name: "Draft/Open",
|
|
672
|
+
is_open: true,
|
|
673
|
+
is_sent: false,
|
|
674
|
+
is_paid: false,
|
|
675
|
+
is_cancelled: false,
|
|
676
|
+
},
|
|
677
|
+
{
|
|
678
|
+
id: 8,
|
|
679
|
+
name: "Versendet/Ausstehend",
|
|
680
|
+
english_name: "Sent/Pending",
|
|
681
|
+
is_open: false,
|
|
682
|
+
is_sent: true,
|
|
683
|
+
is_paid: false,
|
|
684
|
+
is_cancelled: false,
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
id: 9,
|
|
688
|
+
name: "Bezahlt/Abgeschlossen",
|
|
689
|
+
english_name: "Paid/Completed",
|
|
690
|
+
is_open: false,
|
|
691
|
+
is_sent: true,
|
|
692
|
+
is_paid: true,
|
|
693
|
+
is_cancelled: false,
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
id: 19,
|
|
697
|
+
name: "Storniert",
|
|
698
|
+
english_name: "Cancelled",
|
|
699
|
+
is_open: false,
|
|
700
|
+
is_sent: false,
|
|
701
|
+
is_paid: false,
|
|
702
|
+
is_cancelled: true,
|
|
703
|
+
},
|
|
704
|
+
];
|
|
705
|
+
}
|
|
706
|
+
async listAllStatuses(documentType = "all") {
|
|
707
|
+
const statuses = {
|
|
708
|
+
invoices: await this.listInvoiceStatuses(),
|
|
709
|
+
quotes: [
|
|
710
|
+
{ id: 1, name: "Entwurf", english_name: "Draft", document_type: "quote" },
|
|
711
|
+
{ id: 3, name: "Versendet", english_name: "Sent", document_type: "quote" },
|
|
712
|
+
],
|
|
713
|
+
orders: [
|
|
714
|
+
{
|
|
715
|
+
id: 5,
|
|
716
|
+
name: "Bestatigt",
|
|
717
|
+
english_name: "Confirmed",
|
|
718
|
+
document_type: "order",
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
id: 21,
|
|
722
|
+
name: "Wiederkehrend",
|
|
723
|
+
english_name: "Recurring",
|
|
724
|
+
document_type: "order",
|
|
725
|
+
},
|
|
726
|
+
],
|
|
727
|
+
};
|
|
728
|
+
if (documentType === "all") {
|
|
729
|
+
return [...statuses.invoices, ...statuses.quotes, ...statuses.orders];
|
|
730
|
+
}
|
|
731
|
+
return statuses[documentType] || [];
|
|
732
|
+
}
|
|
733
|
+
// ===== PROJECTS =====
|
|
734
|
+
async listProjects(params = {}) {
|
|
735
|
+
return this.makeRequest("GET", "/pr_project", params);
|
|
736
|
+
}
|
|
737
|
+
async getProject(projectId) {
|
|
738
|
+
return this.makeRequest("GET", `/pr_project/${projectId}`);
|
|
739
|
+
}
|
|
740
|
+
async createProject(data) {
|
|
741
|
+
return this.makeRequest("POST", "/pr_project", undefined, data);
|
|
742
|
+
}
|
|
743
|
+
async updateProject(projectId, data) {
|
|
744
|
+
return this.makeRequest("POST", `/pr_project/${projectId}`, undefined, data);
|
|
745
|
+
}
|
|
746
|
+
async deleteProject(projectId) {
|
|
747
|
+
return this.makeRequest("DELETE", `/pr_project/${projectId}`);
|
|
748
|
+
}
|
|
749
|
+
async archiveProject(projectId) {
|
|
750
|
+
return this.makeRequest("POST", `/pr_project/${projectId}/archive`);
|
|
751
|
+
}
|
|
752
|
+
async unarchiveProject(projectId) {
|
|
753
|
+
return this.makeRequest("POST", `/pr_project/${projectId}/unarchive`);
|
|
754
|
+
}
|
|
755
|
+
async searchProjects(searchParams) {
|
|
756
|
+
return this.makeRequest("POST", "/pr_project/search", undefined, searchParams);
|
|
757
|
+
}
|
|
758
|
+
// ===== PROJECT TYPES =====
|
|
759
|
+
async listProjectTypes(params = {}) {
|
|
760
|
+
return this.makeRequest("GET", "/pr_project_type", params);
|
|
761
|
+
}
|
|
762
|
+
async getProjectType(typeId) {
|
|
763
|
+
return this.makeRequest("GET", `/pr_project_type/${typeId}`);
|
|
764
|
+
}
|
|
765
|
+
// ===== PROJECT STATUSES =====
|
|
766
|
+
async listProjectStatuses(params = {}) {
|
|
767
|
+
return this.makeRequest("GET", "/pr_project_state", params);
|
|
768
|
+
}
|
|
769
|
+
async getProjectStatus(statusId) {
|
|
770
|
+
return this.makeRequest("GET", `/pr_project_state/${statusId}`);
|
|
771
|
+
}
|
|
772
|
+
// ===== MILESTONES (PROJ-04) =====
|
|
773
|
+
async listMilestones(projectId, params = {}) {
|
|
774
|
+
return this.makeRequest("GET", `/pr_project/${projectId}/milestone`, params);
|
|
775
|
+
}
|
|
776
|
+
async getMilestone(projectId, milestoneId) {
|
|
777
|
+
return this.makeRequest("GET", `/pr_project/${projectId}/milestone/${milestoneId}`);
|
|
778
|
+
}
|
|
779
|
+
async createMilestone(projectId, data) {
|
|
780
|
+
return this.makeRequest("POST", `/pr_project/${projectId}/milestone`, undefined, data);
|
|
781
|
+
}
|
|
782
|
+
async deleteMilestone(projectId, milestoneId) {
|
|
783
|
+
return this.makeRequest("DELETE", `/pr_project/${projectId}/milestone/${milestoneId}`);
|
|
784
|
+
}
|
|
785
|
+
// ===== WORK PACKAGES (PROJ-05) =====
|
|
786
|
+
async listWorkPackages(projectId, params = {}) {
|
|
787
|
+
return this.makeRequest("GET", `/pr_project/${projectId}/workpackage`, params);
|
|
788
|
+
}
|
|
789
|
+
async getWorkPackage(projectId, workpackageId) {
|
|
790
|
+
return this.makeRequest("GET", `/pr_project/${projectId}/workpackage/${workpackageId}`);
|
|
791
|
+
}
|
|
792
|
+
async createWorkPackage(projectId, data) {
|
|
793
|
+
return this.makeRequest("POST", `/pr_project/${projectId}/workpackage`, undefined, data);
|
|
794
|
+
}
|
|
795
|
+
async updateWorkPackage(projectId, workpackageId, data) {
|
|
796
|
+
return this.makeRequest("PATCH", `/pr_project/${projectId}/workpackage/${workpackageId}`, undefined, data);
|
|
797
|
+
}
|
|
798
|
+
async deleteWorkPackage(projectId, workpackageId) {
|
|
799
|
+
return this.makeRequest("DELETE", `/pr_project/${projectId}/workpackage/${workpackageId}`);
|
|
800
|
+
}
|
|
801
|
+
// ===== TIMESHEETS (PROJ-06) =====
|
|
802
|
+
// Note: Duration format is "HH:MM" (e.g., "02:30" for 2.5 hours)
|
|
803
|
+
async listTimesheets(params = {}) {
|
|
804
|
+
return this.makeRequest("GET", "/timesheet", params);
|
|
805
|
+
}
|
|
806
|
+
async getTimesheet(timesheetId) {
|
|
807
|
+
return this.makeRequest("GET", `/timesheet/${timesheetId}`);
|
|
808
|
+
}
|
|
809
|
+
async createTimesheet(data) {
|
|
810
|
+
return this.makeRequest("POST", "/timesheet", undefined, data);
|
|
811
|
+
}
|
|
812
|
+
async deleteTimesheet(timesheetId) {
|
|
813
|
+
return this.makeRequest("DELETE", `/timesheet/${timesheetId}`);
|
|
814
|
+
}
|
|
815
|
+
async searchTimesheets(searchParams) {
|
|
816
|
+
return this.makeRequest("POST", "/timesheet/search", undefined, searchParams);
|
|
817
|
+
}
|
|
818
|
+
// ===== TIMESHEET STATUSES (PROJ-07) =====
|
|
819
|
+
async listTimesheetStatuses() {
|
|
820
|
+
return this.makeRequest("GET", "/timesheet_status");
|
|
821
|
+
}
|
|
822
|
+
// ===== BUSINESS ACTIVITIES (PROJ-08) =====
|
|
823
|
+
// Also known as "client_service" in Bexio API
|
|
824
|
+
async listBusinessActivities(params = {}) {
|
|
825
|
+
return this.makeRequest("GET", "/client_service", params);
|
|
826
|
+
}
|
|
827
|
+
async getBusinessActivity(activityId) {
|
|
828
|
+
return this.makeRequest("GET", `/client_service/${activityId}`);
|
|
829
|
+
}
|
|
830
|
+
async createBusinessActivity(data) {
|
|
831
|
+
return this.makeRequest("POST", "/client_service", undefined, data);
|
|
832
|
+
}
|
|
833
|
+
// ===== COMMUNICATION TYPES (PROJ-09) =====
|
|
834
|
+
async listCommunicationTypes(params = {}) {
|
|
835
|
+
return this.makeRequest("GET", "/communication_kind", params);
|
|
836
|
+
}
|
|
837
|
+
async getCommunicationType(typeId) {
|
|
838
|
+
return this.makeRequest("GET", `/communication_kind/${typeId}`);
|
|
839
|
+
}
|
|
840
|
+
// ===== ACCOUNTS (Chart of Accounts - ACCT-01) =====
|
|
841
|
+
async listAccounts(params = {}) {
|
|
842
|
+
return this.makeRequest("GET", "/accounts", params);
|
|
843
|
+
}
|
|
844
|
+
async getAccount(accountId) {
|
|
845
|
+
return this.makeRequest("GET", `/accounts/${accountId}`);
|
|
846
|
+
}
|
|
847
|
+
async createAccount(data) {
|
|
848
|
+
return this.makeRequest("POST", "/accounts", undefined, data);
|
|
849
|
+
}
|
|
850
|
+
async searchAccounts(searchParams) {
|
|
851
|
+
return this.makeRequest("POST", "/accounts/search", undefined, searchParams);
|
|
852
|
+
}
|
|
853
|
+
// ===== ACCOUNT GROUPS (ACCT-02) =====
|
|
854
|
+
async listAccountGroups(params = {}) {
|
|
855
|
+
return this.makeRequest("GET", "/account_groups", params);
|
|
856
|
+
}
|
|
857
|
+
// ===== CALENDAR YEARS (ACCT-03) =====
|
|
858
|
+
async listCalendarYears(params = {}) {
|
|
859
|
+
return this.makeRequest("GET", "/calendar_year", params);
|
|
860
|
+
}
|
|
861
|
+
async getCalendarYear(yearId) {
|
|
862
|
+
return this.makeRequest("GET", `/calendar_year/${yearId}`);
|
|
863
|
+
}
|
|
864
|
+
// ===== BUSINESS YEARS (ACCT-04) =====
|
|
865
|
+
async listBusinessYears(params = {}) {
|
|
866
|
+
return this.makeRequest("GET", "/business_year", params);
|
|
867
|
+
}
|
|
868
|
+
// ===== MANUAL ENTRIES (ACCT-05) =====
|
|
869
|
+
async listManualEntries(params = {}) {
|
|
870
|
+
return this.makeRequest("GET", "/manual_entry", params);
|
|
871
|
+
}
|
|
872
|
+
async getManualEntry(entryId) {
|
|
873
|
+
return this.makeRequest("GET", `/manual_entry/${entryId}`);
|
|
874
|
+
}
|
|
875
|
+
async createManualEntry(data) {
|
|
876
|
+
return this.makeRequest("POST", "/manual_entry", undefined, data);
|
|
877
|
+
}
|
|
878
|
+
async updateManualEntry(entryId, data) {
|
|
879
|
+
return this.makeRequest("PUT", `/manual_entry/${entryId}`, undefined, data);
|
|
880
|
+
}
|
|
881
|
+
async deleteManualEntry(entryId) {
|
|
882
|
+
return this.makeRequest("DELETE", `/manual_entry/${entryId}`);
|
|
883
|
+
}
|
|
884
|
+
// ===== VAT PERIODS (ACCT-06) =====
|
|
885
|
+
async listVatPeriods(params = {}) {
|
|
886
|
+
return this.makeRequest("GET", "/vat_period", params);
|
|
887
|
+
}
|
|
888
|
+
// ===== ACCOUNTING JOURNAL (ACCT-07) =====
|
|
889
|
+
async getJournal(params) {
|
|
890
|
+
return this.makeRequest("GET", "/journal", params);
|
|
891
|
+
}
|
|
892
|
+
// ===== BILLS (Creditor Invoices - PURCH-01) =====
|
|
893
|
+
async listBills(params = {}) {
|
|
894
|
+
return this.makeRequest("GET", "/kb_bill", params);
|
|
895
|
+
}
|
|
896
|
+
async getBill(billId) {
|
|
897
|
+
return this.makeRequest("GET", `/kb_bill/${billId}`);
|
|
898
|
+
}
|
|
899
|
+
async createBill(data) {
|
|
900
|
+
return this.makeRequest("POST", "/kb_bill", undefined, data);
|
|
901
|
+
}
|
|
902
|
+
async updateBill(billId, data) {
|
|
903
|
+
return this.makeRequest("POST", `/kb_bill/${billId}`, undefined, data);
|
|
904
|
+
}
|
|
905
|
+
async deleteBill(billId) {
|
|
906
|
+
return this.makeRequest("DELETE", `/kb_bill/${billId}`);
|
|
907
|
+
}
|
|
908
|
+
async searchBills(searchParams, queryParams) {
|
|
909
|
+
return this.makeRequest("POST", "/kb_bill/search", queryParams, searchParams);
|
|
910
|
+
}
|
|
911
|
+
async issueBill(billId) {
|
|
912
|
+
return this.makeRequest("POST", `/kb_bill/${billId}/issue`);
|
|
913
|
+
}
|
|
914
|
+
async markBillAsPaid(billId) {
|
|
915
|
+
return this.makeRequest("POST", `/kb_bill/${billId}/mark_as_paid`);
|
|
916
|
+
}
|
|
917
|
+
// ===== EXPENSES (PURCH-02) =====
|
|
918
|
+
async listExpenses(params = {}) {
|
|
919
|
+
return this.makeRequest("GET", "/kb_expense", params);
|
|
920
|
+
}
|
|
921
|
+
async getExpense(expenseId) {
|
|
922
|
+
return this.makeRequest("GET", `/kb_expense/${expenseId}`);
|
|
923
|
+
}
|
|
924
|
+
async createExpense(data) {
|
|
925
|
+
return this.makeRequest("POST", "/kb_expense", undefined, data);
|
|
926
|
+
}
|
|
927
|
+
async updateExpense(expenseId, data) {
|
|
928
|
+
return this.makeRequest("POST", `/kb_expense/${expenseId}`, undefined, data);
|
|
929
|
+
}
|
|
930
|
+
async deleteExpense(expenseId) {
|
|
931
|
+
return this.makeRequest("DELETE", `/kb_expense/${expenseId}`);
|
|
932
|
+
}
|
|
933
|
+
// ===== PURCHASE ORDERS (PURCH-03) =====
|
|
934
|
+
async listPurchaseOrders(params = {}) {
|
|
935
|
+
return this.makeRequest("GET", "/purchase_order", params);
|
|
936
|
+
}
|
|
937
|
+
async getPurchaseOrder(purchaseOrderId) {
|
|
938
|
+
return this.makeRequest("GET", `/purchase_order/${purchaseOrderId}`);
|
|
939
|
+
}
|
|
940
|
+
async createPurchaseOrder(data) {
|
|
941
|
+
return this.makeRequest("POST", "/purchase_order", undefined, data);
|
|
942
|
+
}
|
|
943
|
+
async updatePurchaseOrder(purchaseOrderId, data) {
|
|
944
|
+
return this.makeRequest("POST", `/purchase_order/${purchaseOrderId}`, undefined, data);
|
|
945
|
+
}
|
|
946
|
+
async deletePurchaseOrder(purchaseOrderId) {
|
|
947
|
+
return this.makeRequest("DELETE", `/purchase_order/${purchaseOrderId}`);
|
|
948
|
+
}
|
|
949
|
+
// ===== OUTGOING PAYMENTS (linked to bills - PURCH-04) =====
|
|
950
|
+
// Note: Uses nested URL pattern /kb_bill/{id}/payment (mirrors incoming payments on invoices)
|
|
951
|
+
async listOutgoingPayments(billId) {
|
|
952
|
+
return this.makeRequest("GET", `/kb_bill/${billId}/payment`);
|
|
953
|
+
}
|
|
954
|
+
async getOutgoingPayment(billId, paymentId) {
|
|
955
|
+
return this.makeRequest("GET", `/kb_bill/${billId}/payment/${paymentId}`);
|
|
956
|
+
}
|
|
957
|
+
async createOutgoingPayment(billId, paymentData) {
|
|
958
|
+
return this.makeRequest("POST", `/kb_bill/${billId}/payment`, undefined, paymentData);
|
|
959
|
+
}
|
|
960
|
+
async updateOutgoingPayment(billId, paymentId, paymentData) {
|
|
961
|
+
return this.makeRequest("POST", `/kb_bill/${billId}/payment/${paymentId}`, undefined, paymentData);
|
|
962
|
+
}
|
|
963
|
+
async deleteOutgoingPayment(billId, paymentId) {
|
|
964
|
+
return this.makeRequest("DELETE", `/kb_bill/${billId}/payment/${paymentId}`);
|
|
965
|
+
}
|
|
966
|
+
// ===== EMPLOYEES (PAY-01) =====
|
|
967
|
+
// Note: Payroll module may not be enabled - handlers check availability
|
|
968
|
+
async listEmployees(params = {}) {
|
|
969
|
+
return this.makeRequest("GET", "/employee", params);
|
|
970
|
+
}
|
|
971
|
+
async getEmployee(employeeId) {
|
|
972
|
+
return this.makeRequest("GET", `/employee/${employeeId}`);
|
|
973
|
+
}
|
|
974
|
+
async createEmployee(data) {
|
|
975
|
+
return this.makeRequest("POST", "/employee", undefined, data);
|
|
976
|
+
}
|
|
977
|
+
async updateEmployee(employeeId, data) {
|
|
978
|
+
return this.makeRequest("POST", `/employee/${employeeId}`, undefined, data);
|
|
979
|
+
}
|
|
980
|
+
// ===== ABSENCES (PAY-02) =====
|
|
981
|
+
async listAbsences(params = {}) {
|
|
982
|
+
return this.makeRequest("GET", "/absence", params);
|
|
983
|
+
}
|
|
984
|
+
async getAbsence(absenceId) {
|
|
985
|
+
return this.makeRequest("GET", `/absence/${absenceId}`);
|
|
986
|
+
}
|
|
987
|
+
async createAbsence(data) {
|
|
988
|
+
return this.makeRequest("POST", "/absence", undefined, data);
|
|
989
|
+
}
|
|
990
|
+
async updateAbsence(absenceId, data) {
|
|
991
|
+
return this.makeRequest("POST", `/absence/${absenceId}`, undefined, data);
|
|
992
|
+
}
|
|
993
|
+
async deleteAbsence(absenceId) {
|
|
994
|
+
return this.makeRequest("DELETE", `/absence/${absenceId}`);
|
|
995
|
+
}
|
|
996
|
+
// ===== PAYROLL DOCUMENTS (PAY-03) =====
|
|
997
|
+
async listPayrollDocuments(params = {}) {
|
|
998
|
+
return this.makeRequest("GET", "/payroll_document", params);
|
|
999
|
+
}
|
|
1000
|
+
// ===== FILES (FILE-01) =====
|
|
1001
|
+
async listFiles(params = {}) {
|
|
1002
|
+
return this.makeRequest("GET", "/file", params);
|
|
1003
|
+
}
|
|
1004
|
+
async getFile(fileId) {
|
|
1005
|
+
return this.makeRequest("GET", `/file/${fileId}`);
|
|
1006
|
+
}
|
|
1007
|
+
async uploadFile(data) {
|
|
1008
|
+
const buffer = Buffer.from(data.content_base64, "base64");
|
|
1009
|
+
// Use form-data for multipart upload (transitive dep of axios)
|
|
1010
|
+
const FormData = (await import("form-data")).default;
|
|
1011
|
+
const formData = new FormData();
|
|
1012
|
+
formData.append("file", buffer, {
|
|
1013
|
+
filename: data.name,
|
|
1014
|
+
contentType: data.content_type,
|
|
1015
|
+
});
|
|
1016
|
+
return this.client.post("/file", formData, {
|
|
1017
|
+
headers: formData.getHeaders(),
|
|
1018
|
+
}).then(r => r.data);
|
|
1019
|
+
}
|
|
1020
|
+
async downloadFile(fileId) {
|
|
1021
|
+
const response = await this.client.get(`/file/${fileId}/download`, {
|
|
1022
|
+
responseType: "arraybuffer",
|
|
1023
|
+
});
|
|
1024
|
+
return Buffer.from(response.data).toString("base64");
|
|
1025
|
+
}
|
|
1026
|
+
async updateFile(fileId, data) {
|
|
1027
|
+
return this.makeRequest("POST", `/file/${fileId}`, undefined, data);
|
|
1028
|
+
}
|
|
1029
|
+
async deleteFile(fileId) {
|
|
1030
|
+
return this.makeRequest("DELETE", `/file/${fileId}`);
|
|
1031
|
+
}
|
|
1032
|
+
// ===== ADDITIONAL ADDRESSES (FILE-02) =====
|
|
1033
|
+
async listAdditionalAddresses(contactId, params = {}) {
|
|
1034
|
+
return this.makeRequest("GET", `/contact/${contactId}/additional_address`, params);
|
|
1035
|
+
}
|
|
1036
|
+
async getAdditionalAddress(contactId, addressId) {
|
|
1037
|
+
return this.makeRequest("GET", `/contact/${contactId}/additional_address/${addressId}`);
|
|
1038
|
+
}
|
|
1039
|
+
async createAdditionalAddress(contactId, data) {
|
|
1040
|
+
return this.makeRequest("POST", `/contact/${contactId}/additional_address`, undefined, data);
|
|
1041
|
+
}
|
|
1042
|
+
async deleteAdditionalAddress(contactId, addressId) {
|
|
1043
|
+
return this.makeRequest("DELETE", `/contact/${contactId}/additional_address/${addressId}`);
|
|
1044
|
+
}
|
|
1045
|
+
}
|