@agnocon/piece-bexio 0.1.7

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.
Files changed (182) hide show
  1. package/LICENSE.MIT-AP +24 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +93 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/lib/actions/create-company.d.ts +28 -0
  7. package/dist/lib/actions/create-company.d.ts.map +1 -0
  8. package/dist/lib/actions/create-company.js +461 -0
  9. package/dist/lib/actions/create-company.js.map +1 -0
  10. package/dist/lib/actions/create-file.d.ts +4 -0
  11. package/dist/lib/actions/create-file.d.ts.map +1 -0
  12. package/dist/lib/actions/create-file.js +48 -0
  13. package/dist/lib/actions/create-file.js.map +1 -0
  14. package/dist/lib/actions/create-manual-entry.d.ts +7 -0
  15. package/dist/lib/actions/create-manual-entry.d.ts.map +1 -0
  16. package/dist/lib/actions/create-manual-entry.js +426 -0
  17. package/dist/lib/actions/create-manual-entry.js.map +1 -0
  18. package/dist/lib/actions/create-person.d.ts +30 -0
  19. package/dist/lib/actions/create-person.d.ts.map +1 -0
  20. package/dist/lib/actions/create-person.js +477 -0
  21. package/dist/lib/actions/create-person.js.map +1 -0
  22. package/dist/lib/actions/create-product.d.ts +34 -0
  23. package/dist/lib/actions/create-product.d.ts.map +1 -0
  24. package/dist/lib/actions/create-product.js +527 -0
  25. package/dist/lib/actions/create-product.js.map +1 -0
  26. package/dist/lib/actions/create-project.d.ts +17 -0
  27. package/dist/lib/actions/create-project.d.ts.map +1 -0
  28. package/dist/lib/actions/create-project.js +316 -0
  29. package/dist/lib/actions/create-project.js.map +1 -0
  30. package/dist/lib/actions/create-sales-invoice.d.ts +25 -0
  31. package/dist/lib/actions/create-sales-invoice.d.ts.map +1 -0
  32. package/dist/lib/actions/create-sales-invoice.js +615 -0
  33. package/dist/lib/actions/create-sales-invoice.js.map +1 -0
  34. package/dist/lib/actions/create-sales-order.d.ts +25 -0
  35. package/dist/lib/actions/create-sales-order.d.ts.map +1 -0
  36. package/dist/lib/actions/create-sales-order.js +642 -0
  37. package/dist/lib/actions/create-sales-order.js.map +1 -0
  38. package/dist/lib/actions/create-sales-quote.d.ts +28 -0
  39. package/dist/lib/actions/create-sales-quote.d.ts.map +1 -0
  40. package/dist/lib/actions/create-sales-quote.js +666 -0
  41. package/dist/lib/actions/create-sales-quote.js.map +1 -0
  42. package/dist/lib/actions/create-time-tracking.d.ts +17 -0
  43. package/dist/lib/actions/create-time-tracking.d.ts.map +1 -0
  44. package/dist/lib/actions/create-time-tracking.js +380 -0
  45. package/dist/lib/actions/create-time-tracking.js.map +1 -0
  46. package/dist/lib/actions/export-invoice-pdf.d.ts +5 -0
  47. package/dist/lib/actions/export-invoice-pdf.d.ts.map +1 -0
  48. package/dist/lib/actions/export-invoice-pdf.js +94 -0
  49. package/dist/lib/actions/export-invoice-pdf.js.map +1 -0
  50. package/dist/lib/actions/find-account.d.ts +6 -0
  51. package/dist/lib/actions/find-account.d.ts.map +1 -0
  52. package/dist/lib/actions/find-account.js +107 -0
  53. package/dist/lib/actions/find-account.js.map +1 -0
  54. package/dist/lib/actions/find-company.d.ts +8 -0
  55. package/dist/lib/actions/find-company.d.ts.map +1 -0
  56. package/dist/lib/actions/find-company.js +160 -0
  57. package/dist/lib/actions/find-company.js.map +1 -0
  58. package/dist/lib/actions/find-country.d.ts +7 -0
  59. package/dist/lib/actions/find-country.d.ts.map +1 -0
  60. package/dist/lib/actions/find-country.js +125 -0
  61. package/dist/lib/actions/find-country.js.map +1 -0
  62. package/dist/lib/actions/find-person.d.ts +9 -0
  63. package/dist/lib/actions/find-person.d.ts.map +1 -0
  64. package/dist/lib/actions/find-person.js +175 -0
  65. package/dist/lib/actions/find-person.js.map +1 -0
  66. package/dist/lib/actions/find-product.d.ts +7 -0
  67. package/dist/lib/actions/find-product.d.ts.map +1 -0
  68. package/dist/lib/actions/find-product.js +124 -0
  69. package/dist/lib/actions/find-product.js.map +1 -0
  70. package/dist/lib/actions/search-invoice.d.ts +7 -0
  71. package/dist/lib/actions/search-invoice.d.ts.map +1 -0
  72. package/dist/lib/actions/search-invoice.js +140 -0
  73. package/dist/lib/actions/search-invoice.js.map +1 -0
  74. package/dist/lib/actions/search-order.d.ts +7 -0
  75. package/dist/lib/actions/search-order.d.ts.map +1 -0
  76. package/dist/lib/actions/search-order.js +139 -0
  77. package/dist/lib/actions/search-order.js.map +1 -0
  78. package/dist/lib/actions/search-quote.d.ts +7 -0
  79. package/dist/lib/actions/search-quote.d.ts.map +1 -0
  80. package/dist/lib/actions/search-quote.js +140 -0
  81. package/dist/lib/actions/search-quote.js.map +1 -0
  82. package/dist/lib/actions/send-sales-invoice.d.ts +9 -0
  83. package/dist/lib/actions/send-sales-invoice.d.ts.map +1 -0
  84. package/dist/lib/actions/send-sales-invoice.js +110 -0
  85. package/dist/lib/actions/send-sales-invoice.js.map +1 -0
  86. package/dist/lib/actions/update-company.d.ts +29 -0
  87. package/dist/lib/actions/update-company.d.ts.map +1 -0
  88. package/dist/lib/actions/update-company.js +506 -0
  89. package/dist/lib/actions/update-company.js.map +1 -0
  90. package/dist/lib/actions/update-person.d.ts +31 -0
  91. package/dist/lib/actions/update-person.d.ts.map +1 -0
  92. package/dist/lib/actions/update-person.js +524 -0
  93. package/dist/lib/actions/update-person.js.map +1 -0
  94. package/dist/lib/actions/update-product.d.ts +34 -0
  95. package/dist/lib/actions/update-product.d.ts.map +1 -0
  96. package/dist/lib/actions/update-product.js +556 -0
  97. package/dist/lib/actions/update-product.js.map +1 -0
  98. package/dist/lib/auth.d.ts +2 -0
  99. package/dist/lib/auth.d.ts.map +1 -0
  100. package/dist/lib/auth.js +51 -0
  101. package/dist/lib/auth.js.map +1 -0
  102. package/dist/lib/common/client.d.ts +13 -0
  103. package/dist/lib/common/client.d.ts.map +1 -0
  104. package/dist/lib/common/client.js +64 -0
  105. package/dist/lib/common/client.js.map +1 -0
  106. package/dist/lib/common/index.d.ts +5 -0
  107. package/dist/lib/common/index.d.ts.map +1 -0
  108. package/dist/lib/common/index.js +10 -0
  109. package/dist/lib/common/index.js.map +1 -0
  110. package/dist/lib/common/props.d.ts +14 -0
  111. package/dist/lib/common/props.d.ts.map +1 -0
  112. package/dist/lib/common/props.js +118 -0
  113. package/dist/lib/common/props.js.map +1 -0
  114. package/dist/lib/common/types.d.ts +89 -0
  115. package/dist/lib/common/types.d.ts.map +1 -0
  116. package/dist/lib/common/types.js +6 -0
  117. package/dist/lib/common/types.js.map +1 -0
  118. package/dist/lib/triggers/new-order.d.ts +11 -0
  119. package/dist/lib/triggers/new-order.d.ts.map +1 -0
  120. package/dist/lib/triggers/new-order.js +152 -0
  121. package/dist/lib/triggers/new-order.js.map +1 -0
  122. package/dist/lib/triggers/new-product.d.ts +3 -0
  123. package/dist/lib/triggers/new-product.d.ts.map +1 -0
  124. package/dist/lib/triggers/new-product.js +111 -0
  125. package/dist/lib/triggers/new-product.js.map +1 -0
  126. package/dist/lib/triggers/new-project.d.ts +11 -0
  127. package/dist/lib/triggers/new-project.d.ts.map +1 -0
  128. package/dist/lib/triggers/new-project.js +141 -0
  129. package/dist/lib/triggers/new-project.js.map +1 -0
  130. package/dist/lib/triggers/new-quote.d.ts +11 -0
  131. package/dist/lib/triggers/new-quote.d.ts.map +1 -0
  132. package/dist/lib/triggers/new-quote.js +153 -0
  133. package/dist/lib/triggers/new-quote.js.map +1 -0
  134. package/dist/lib/triggers/new-sales-invoice.d.ts +11 -0
  135. package/dist/lib/triggers/new-sales-invoice.d.ts.map +1 -0
  136. package/dist/lib/triggers/new-sales-invoice.js +153 -0
  137. package/dist/lib/triggers/new-sales-invoice.js.map +1 -0
  138. package/dist/lib/triggers/new-updated-company.d.ts +3 -0
  139. package/dist/lib/triggers/new-updated-company.d.ts.map +1 -0
  140. package/dist/lib/triggers/new-updated-company.js +122 -0
  141. package/dist/lib/triggers/new-updated-company.js.map +1 -0
  142. package/dist/lib/triggers/new-updated-person.d.ts +3 -0
  143. package/dist/lib/triggers/new-updated-person.d.ts.map +1 -0
  144. package/dist/lib/triggers/new-updated-person.js +122 -0
  145. package/dist/lib/triggers/new-updated-person.js.map +1 -0
  146. package/package.json +48 -0
  147. package/src/index.ts +89 -0
  148. package/src/lib/actions/create-company.ts +464 -0
  149. package/src/lib/actions/create-file.ts +62 -0
  150. package/src/lib/actions/create-manual-entry.ts +445 -0
  151. package/src/lib/actions/create-person.ts +481 -0
  152. package/src/lib/actions/create-product.ts +563 -0
  153. package/src/lib/actions/create-project.ts +344 -0
  154. package/src/lib/actions/create-sales-invoice.ts +656 -0
  155. package/src/lib/actions/create-sales-order.ts +689 -0
  156. package/src/lib/actions/create-sales-quote.ts +713 -0
  157. package/src/lib/actions/create-time-tracking.ts +418 -0
  158. package/src/lib/actions/export-invoice-pdf.ts +104 -0
  159. package/src/lib/actions/find-account.ts +114 -0
  160. package/src/lib/actions/find-company.ts +193 -0
  161. package/src/lib/actions/find-country.ts +127 -0
  162. package/src/lib/actions/find-person.ts +208 -0
  163. package/src/lib/actions/find-product.ts +161 -0
  164. package/src/lib/actions/search-invoice.ts +157 -0
  165. package/src/lib/actions/search-order.ts +155 -0
  166. package/src/lib/actions/search-quote.ts +157 -0
  167. package/src/lib/actions/send-sales-invoice.ts +118 -0
  168. package/src/lib/actions/update-company.ts +518 -0
  169. package/src/lib/actions/update-person.ts +536 -0
  170. package/src/lib/actions/update-product.ts +594 -0
  171. package/src/lib/auth.ts +44 -0
  172. package/src/lib/common/client.ts +65 -0
  173. package/src/lib/common/index.ts +5 -0
  174. package/src/lib/common/props.ts +127 -0
  175. package/src/lib/common/types.ts +99 -0
  176. package/src/lib/triggers/new-order.ts +184 -0
  177. package/src/lib/triggers/new-product.ts +154 -0
  178. package/src/lib/triggers/new-project.ts +165 -0
  179. package/src/lib/triggers/new-quote.ts +186 -0
  180. package/src/lib/triggers/new-sales-invoice.ts +186 -0
  181. package/src/lib/triggers/new-updated-company.ts +161 -0
  182. package/src/lib/triggers/new-updated-person.ts +161 -0
@@ -0,0 +1,594 @@
1
+ import { createAction, Property, OAuth2PropertyValue } from '@agnocon/pieces-framework';
2
+ import { bexioAuth } from '../auth';
3
+ import { BexioClient } from '../common/client';
4
+ import { bexioCommonProps } from '../common/props';
5
+
6
+ export const updateProductAction = createAction({
7
+ auth: bexioAuth,
8
+ name: 'update_product',
9
+ displayName: 'Update Product',
10
+ description: 'Update an existing product or service',
11
+ audience: 'both',
12
+ aiMetadata: { description: 'Updates fields on an existing Bexio product/article (codes, names, prices, tax, unit, stock, dimensions, accounts) identified by its article id; only supplied fields change. Use to modify a known product; locate the article id with Find Product first. Idempotent: re-sending the same values converges to the same product state.', idempotent: true },
13
+ props: {
14
+ article_id: Property.Dropdown({
15
+ auth: bexioAuth,
16
+ displayName: 'Product',
17
+ description: 'Select the product to update',
18
+ required: true,
19
+ refreshers: [],
20
+ options: async ({ auth }) => {
21
+ if (!auth) {
22
+ return {
23
+ disabled: true,
24
+ placeholder: 'Connect your Bexio account first',
25
+ options: [],
26
+ };
27
+ }
28
+
29
+ try {
30
+ const client = new BexioClient(auth);
31
+ const articles = await client.get<Array<{
32
+ id: number;
33
+ intern_code?: string;
34
+ intern_name: string;
35
+ article_type_id?: number;
36
+ }>>('/2.0/article');
37
+
38
+ return {
39
+ disabled: false,
40
+ options: articles.map((article) => {
41
+ const label = article.intern_code
42
+ ? `${article.intern_name} (${article.intern_code})`
43
+ : article.intern_name;
44
+ return {
45
+ label,
46
+ value: article.id,
47
+ };
48
+ }),
49
+ };
50
+ } catch (error) {
51
+ return {
52
+ disabled: true,
53
+ placeholder: 'Failed to load products',
54
+ options: [],
55
+ };
56
+ }
57
+ },
58
+ }),
59
+ user_id: Property.Dropdown({
60
+ auth: bexioAuth,
61
+ displayName: 'User',
62
+ description: 'User associated with this product',
63
+ required: false,
64
+ refreshers: [],
65
+ options: async ({ auth }) => {
66
+ if (!auth) {
67
+ return {
68
+ disabled: true,
69
+ placeholder: 'Connect your Bexio account first',
70
+ options: [],
71
+ };
72
+ }
73
+
74
+ try {
75
+ const client = new BexioClient(auth);
76
+ const users = await client.get<Array<{
77
+ id: number;
78
+ firstname?: string | null;
79
+ lastname?: string | null;
80
+ email: string;
81
+ }>>('/3.0/users');
82
+
83
+ return {
84
+ disabled: false,
85
+ options: users.map((user) => {
86
+ const name = user.firstname && user.lastname
87
+ ? `${user.firstname} ${user.lastname}`
88
+ : user.email;
89
+ return {
90
+ label: name,
91
+ value: user.id,
92
+ };
93
+ }),
94
+ };
95
+ } catch (error) {
96
+ return {
97
+ disabled: true,
98
+ placeholder: 'Failed to load users',
99
+ options: [],
100
+ };
101
+ }
102
+ },
103
+ }),
104
+ intern_code: Property.ShortText({
105
+ displayName: 'Internal Code',
106
+ description: 'Internal product code',
107
+ required: false,
108
+ }),
109
+ intern_name: Property.ShortText({
110
+ displayName: 'Internal Name',
111
+ description: 'Internal product name',
112
+ required: false,
113
+ }),
114
+ intern_description: Property.LongText({
115
+ displayName: 'Internal Description',
116
+ description: 'Internal product description',
117
+ required: false,
118
+ }),
119
+ contact_id: Property.Dropdown({
120
+ auth: bexioAuth,
121
+ displayName: 'Contact',
122
+ description: 'Contact associated with this product',
123
+ required: false,
124
+ refreshers: [],
125
+ options: async ({ auth }) => {
126
+ if (!auth) {
127
+ return {
128
+ disabled: true,
129
+ placeholder: 'Connect your Bexio account first',
130
+ options: [],
131
+ };
132
+ }
133
+
134
+ try {
135
+ const client = new BexioClient(auth);
136
+ const contacts = await client.get<Array<{
137
+ id: number;
138
+ contact_type_id: number;
139
+ name_1: string;
140
+ name_2?: string | null;
141
+ nr?: string | null;
142
+ }>>('/2.0/contact');
143
+
144
+ return {
145
+ disabled: false,
146
+ options: contacts.map((contact) => {
147
+ const name = contact.name_2
148
+ ? `${contact.name_2} ${contact.name_1}`
149
+ : contact.name_1;
150
+ const label = contact.nr ? `${name} (#${contact.nr})` : name;
151
+ return {
152
+ label,
153
+ value: contact.id,
154
+ };
155
+ }),
156
+ };
157
+ } catch (error) {
158
+ return {
159
+ disabled: true,
160
+ placeholder: 'Failed to load contacts',
161
+ options: [],
162
+ };
163
+ }
164
+ },
165
+ }),
166
+ deliverer_code: Property.ShortText({
167
+ displayName: 'Supplier Code',
168
+ description: 'Supplier product code',
169
+ required: false,
170
+ }),
171
+ deliverer_name: Property.ShortText({
172
+ displayName: 'Supplier Name',
173
+ description: 'Supplier product name',
174
+ required: false,
175
+ }),
176
+ deliverer_description: Property.LongText({
177
+ displayName: 'Supplier Description',
178
+ description: 'Supplier product description',
179
+ required: false,
180
+ }),
181
+ purchase_price: Property.ShortText({
182
+ displayName: 'Purchase Price',
183
+ description: 'Purchase price',
184
+ required: false,
185
+ }),
186
+ sale_price: Property.ShortText({
187
+ displayName: 'Sale Price',
188
+ description: 'Sale price',
189
+ required: false,
190
+ }),
191
+ purchase_total: Property.Number({
192
+ displayName: 'Purchase Total',
193
+ description: 'Total purchase amount',
194
+ required: false,
195
+ }),
196
+ sale_total: Property.Number({
197
+ displayName: 'Sale Total',
198
+ description: 'Total sale amount',
199
+ required: false,
200
+ }),
201
+ currency_id: bexioCommonProps.currency({
202
+ displayName: 'Currency',
203
+ required: false,
204
+ }),
205
+ tax_income_id: Property.Dropdown({
206
+ auth: bexioAuth,
207
+ displayName: 'Income Tax',
208
+ description: 'Tax for income/sales',
209
+ required: false,
210
+ refreshers: [],
211
+ options: async ({ auth }) => {
212
+ if (!auth) {
213
+ return {
214
+ disabled: true,
215
+ placeholder: 'Connect your Bexio account first',
216
+ options: [],
217
+ };
218
+ }
219
+
220
+ try {
221
+ const client = new BexioClient(auth);
222
+ const taxes = await client.get<Array<{
223
+ id: number;
224
+ name: string;
225
+ value: number;
226
+ display_name?: string;
227
+ type?: string;
228
+ }>>('/3.0/taxes');
229
+
230
+ return {
231
+ disabled: false,
232
+ options: taxes
233
+ .filter((tax) => tax.type === 'sales_tax' || !tax.type)
234
+ .map((tax) => ({
235
+ label: tax.display_name || tax.name,
236
+ value: tax.id,
237
+ })),
238
+ };
239
+ } catch (error) {
240
+ return {
241
+ disabled: true,
242
+ placeholder: 'Failed to load taxes',
243
+ options: [],
244
+ };
245
+ }
246
+ },
247
+ }),
248
+ tax_expense_id: Property.Dropdown({
249
+ auth: bexioAuth,
250
+ displayName: 'Expense Tax',
251
+ description: 'Tax for expenses/purchases',
252
+ required: false,
253
+ refreshers: [],
254
+ options: async ({ auth }) => {
255
+ if (!auth) {
256
+ return {
257
+ disabled: true,
258
+ placeholder: 'Connect your Bexio account first',
259
+ options: [],
260
+ };
261
+ }
262
+
263
+ try {
264
+ const client = new BexioClient(auth);
265
+ const taxes = await client.get<Array<{
266
+ id: number;
267
+ name: string;
268
+ value: number;
269
+ display_name?: string;
270
+ type?: string;
271
+ }>>('/3.0/taxes');
272
+
273
+ return {
274
+ disabled: false,
275
+ options: taxes
276
+ .filter((tax) => tax.type === 'pre_tax' || !tax.type)
277
+ .map((tax) => ({
278
+ label: tax.display_name || tax.name,
279
+ value: tax.id,
280
+ })),
281
+ };
282
+ } catch (error) {
283
+ return {
284
+ disabled: true,
285
+ placeholder: 'Failed to load taxes',
286
+ options: [],
287
+ };
288
+ }
289
+ },
290
+ }),
291
+ unit_id: Property.Dropdown({
292
+ auth: bexioAuth,
293
+ displayName: 'Unit',
294
+ description: 'Unit of measurement',
295
+ required: false,
296
+ refreshers: [],
297
+ options: async ({ auth }) => {
298
+ if (!auth) {
299
+ return {
300
+ disabled: true,
301
+ placeholder: 'Connect your Bexio account first',
302
+ options: [],
303
+ };
304
+ }
305
+
306
+ try {
307
+ const client = new BexioClient(auth);
308
+ const units = await client.get<Array<{ id: number; name: string }>>('/2.0/unit');
309
+
310
+ return {
311
+ disabled: false,
312
+ options: units.map((unit) => ({
313
+ label: unit.name,
314
+ value: unit.id,
315
+ })),
316
+ };
317
+ } catch (error) {
318
+ return {
319
+ disabled: true,
320
+ placeholder: 'Failed to load units',
321
+ options: [],
322
+ };
323
+ }
324
+ },
325
+ }),
326
+ is_stock: Property.Checkbox({
327
+ displayName: 'Is Stock Item',
328
+ description: 'Whether this is a stock item (requires stock_edit scope)',
329
+ required: false,
330
+ }),
331
+ stock_id: Property.Dropdown({
332
+ auth: bexioAuth,
333
+ displayName: 'Stock Location',
334
+ description: 'Stock location',
335
+ required: false,
336
+ refreshers: [],
337
+ options: async ({ auth }) => {
338
+ if (!auth) {
339
+ return {
340
+ disabled: true,
341
+ placeholder: 'Connect your Bexio account first',
342
+ options: [],
343
+ };
344
+ }
345
+
346
+ try {
347
+ const client = new BexioClient(auth);
348
+ const stocks = await client.get<Array<{ id: number; name: string }>>('/2.0/stock').catch(() => []);
349
+
350
+ return {
351
+ disabled: false,
352
+ options: stocks.map((stock) => ({
353
+ label: stock.name,
354
+ value: stock.id,
355
+ })),
356
+ };
357
+ } catch (error) {
358
+ return {
359
+ disabled: true,
360
+ placeholder: 'Failed to load stock locations',
361
+ options: [],
362
+ };
363
+ }
364
+ },
365
+ }),
366
+ stock_place_id: Property.Dropdown({
367
+ auth: bexioAuth,
368
+ displayName: 'Stock Area',
369
+ description: 'Stock area/place',
370
+ required: false,
371
+ refreshers: [],
372
+ options: async ({ auth }) => {
373
+ if (!auth) {
374
+ return {
375
+ disabled: true,
376
+ placeholder: 'Connect your Bexio account first',
377
+ options: [],
378
+ };
379
+ }
380
+
381
+ try {
382
+ const client = new BexioClient(auth);
383
+ const stockPlaces = await client.get<Array<{ id: number; name: string }>>('/2.0/stock_place').catch(() => []);
384
+
385
+ return {
386
+ disabled: false,
387
+ options: stockPlaces.map((place) => ({
388
+ label: place.name,
389
+ value: place.id,
390
+ })),
391
+ };
392
+ } catch (error) {
393
+ return {
394
+ disabled: true,
395
+ placeholder: 'Failed to load stock areas',
396
+ options: [],
397
+ };
398
+ }
399
+ },
400
+ }),
401
+ stock_nr: Property.Number({
402
+ displayName: 'Stock Number',
403
+ description: 'Current stock quantity (can only be set if no bookings exist)',
404
+ required: false,
405
+ }),
406
+ stock_min_nr: Property.Number({
407
+ displayName: 'Minimum Stock',
408
+ description: 'Minimum stock quantity',
409
+ required: false,
410
+ }),
411
+ width: Property.Number({
412
+ displayName: 'Width',
413
+ description: 'Product width',
414
+ required: false,
415
+ }),
416
+ height: Property.Number({
417
+ displayName: 'Height',
418
+ description: 'Product height',
419
+ required: false,
420
+ }),
421
+ weight: Property.Number({
422
+ displayName: 'Weight',
423
+ description: 'Product weight',
424
+ required: false,
425
+ }),
426
+ volume: Property.Number({
427
+ displayName: 'Volume',
428
+ description: 'Product volume',
429
+ required: false,
430
+ }),
431
+ remarks: Property.LongText({
432
+ displayName: 'Remarks',
433
+ description: 'Additional remarks',
434
+ required: false,
435
+ }),
436
+ delivery_price: Property.Number({
437
+ displayName: 'Delivery Price',
438
+ description: 'Delivery price',
439
+ required: false,
440
+ }),
441
+ article_group_id: Property.Dropdown({
442
+ auth: bexioAuth,
443
+ displayName: 'Article Group',
444
+ description: 'Product group/category',
445
+ required: false,
446
+ refreshers: [],
447
+ options: async ({ auth }) => {
448
+ if (!auth) {
449
+ return {
450
+ disabled: true,
451
+ placeholder: 'Connect your Bexio account first',
452
+ options: [],
453
+ };
454
+ }
455
+
456
+ try {
457
+ const client = new BexioClient(auth);
458
+ const groups = await client.get<Array<{ id: number; name: string }>>('/2.0/article_group').catch(() => []);
459
+
460
+ return {
461
+ disabled: false,
462
+ options: groups.map((group) => ({
463
+ label: group.name,
464
+ value: group.id,
465
+ })),
466
+ };
467
+ } catch (error) {
468
+ return {
469
+ disabled: true,
470
+ placeholder: 'Failed to load article groups',
471
+ options: [],
472
+ };
473
+ }
474
+ },
475
+ }),
476
+ account_id: bexioCommonProps.account({
477
+ displayName: 'Account',
478
+ description: 'Account for this product',
479
+ required: false,
480
+ }),
481
+ expense_account_id: bexioCommonProps.account({
482
+ displayName: 'Expense Account',
483
+ description: 'Expense account for this product',
484
+ required: false,
485
+ }),
486
+ },
487
+ async run({ auth, propsValue }) {
488
+ const client = new BexioClient(auth);
489
+ const props = propsValue;
490
+ const articleId = props['article_id'] as number;
491
+
492
+ const requestBody: Record<string, unknown> = {};
493
+
494
+ if (props['user_id']) {
495
+ requestBody['user_id'] = props['user_id'];
496
+ }
497
+ if (props['intern_code']) {
498
+ requestBody['intern_code'] = props['intern_code'];
499
+ }
500
+ if (props['intern_name']) {
501
+ requestBody['intern_name'] = props['intern_name'];
502
+ }
503
+ if (props['intern_description']) {
504
+ requestBody['intern_description'] = props['intern_description'];
505
+ }
506
+ if (props['contact_id']) {
507
+ requestBody['contact_id'] = props['contact_id'];
508
+ }
509
+ if (props['deliverer_code']) {
510
+ requestBody['deliverer_code'] = props['deliverer_code'];
511
+ }
512
+ if (props['deliverer_name']) {
513
+ requestBody['deliverer_name'] = props['deliverer_name'];
514
+ }
515
+ if (props['deliverer_description']) {
516
+ requestBody['deliverer_description'] = props['deliverer_description'];
517
+ }
518
+ if (props['purchase_price']) {
519
+ requestBody['purchase_price'] = props['purchase_price'];
520
+ }
521
+ if (props['sale_price']) {
522
+ requestBody['sale_price'] = props['sale_price'];
523
+ }
524
+ if (props['purchase_total']) {
525
+ requestBody['purchase_total'] = props['purchase_total'];
526
+ }
527
+ if (props['sale_total']) {
528
+ requestBody['sale_total'] = props['sale_total'];
529
+ }
530
+ if (props['currency_id']) {
531
+ requestBody['currency_id'] = props['currency_id'];
532
+ }
533
+ if (props['tax_income_id']) {
534
+ requestBody['tax_income_id'] = props['tax_income_id'];
535
+ }
536
+ if (props['tax_expense_id']) {
537
+ requestBody['tax_expense_id'] = props['tax_expense_id'];
538
+ }
539
+ if (props['unit_id']) {
540
+ requestBody['unit_id'] = props['unit_id'];
541
+ }
542
+ if (props['is_stock'] !== undefined) {
543
+ requestBody['is_stock'] = props['is_stock'];
544
+ }
545
+ if (props['stock_id']) {
546
+ requestBody['stock_id'] = props['stock_id'];
547
+ }
548
+ if (props['stock_place_id']) {
549
+ requestBody['stock_place_id'] = props['stock_place_id'];
550
+ }
551
+ if (props['stock_nr'] !== undefined) {
552
+ requestBody['stock_nr'] = props['stock_nr'];
553
+ }
554
+ if (props['stock_min_nr'] !== undefined) {
555
+ requestBody['stock_min_nr'] = props['stock_min_nr'];
556
+ }
557
+ if (props['width']) {
558
+ requestBody['width'] = props['width'];
559
+ }
560
+ if (props['height']) {
561
+ requestBody['height'] = props['height'];
562
+ }
563
+ if (props['weight']) {
564
+ requestBody['weight'] = props['weight'];
565
+ }
566
+ if (props['volume']) {
567
+ requestBody['volume'] = props['volume'];
568
+ }
569
+ if (props['remarks']) {
570
+ requestBody['remarks'] = props['remarks'];
571
+ }
572
+ if (props['delivery_price']) {
573
+ requestBody['delivery_price'] = props['delivery_price'];
574
+ }
575
+ if (props['article_group_id']) {
576
+ requestBody['article_group_id'] = props['article_group_id'];
577
+ }
578
+ if (props['account_id']) {
579
+ requestBody['account_id'] = props['account_id'];
580
+ }
581
+ if (props['expense_account_id']) {
582
+ requestBody['expense_account_id'] = props['expense_account_id'];
583
+ }
584
+
585
+ const response = await client.post<{
586
+ id: number;
587
+ intern_code: string;
588
+ intern_name: string;
589
+ }>(`/2.0/article/${articleId}`, requestBody);
590
+
591
+ return response;
592
+ },
593
+ });
594
+
@@ -0,0 +1,44 @@
1
+ import { PieceAuth } from '@agnocon/pieces-framework';
2
+ import { BexioClient } from './common/client';
3
+
4
+ export const bexioAuth = PieceAuth.OAuth2({
5
+ authUrl: 'https://auth.bexio.com/realms/bexio/protocol/openid-connect/auth',
6
+ tokenUrl: 'https://auth.bexio.com/realms/bexio/protocol/openid-connect/token',
7
+ required: true,
8
+ scope: [
9
+ 'openid',
10
+ 'profile',
11
+ 'email',
12
+ 'offline_access',
13
+ 'contact_show',
14
+ 'contact_edit',
15
+ 'article_show',
16
+ 'article_edit',
17
+ 'kb_invoice_show',
18
+ 'kb_invoice_edit',
19
+ 'kb_offer_show',
20
+ 'kb_offer_edit',
21
+ 'kb_order_show',
22
+ 'kb_order_edit',
23
+ 'project_show',
24
+ 'project_edit',
25
+ 'task_show',
26
+ 'monitoring_edit',
27
+ 'accounting',
28
+ 'file',
29
+ ],
30
+ validate: async ({ auth }) => {
31
+ try {
32
+ const client = new BexioClient(auth);
33
+ await client.get('/users/me');
34
+ return {
35
+ valid: true,
36
+ };
37
+ } catch (error) {
38
+ return {
39
+ valid: false,
40
+ error: 'Authentication failed. Please check your connection and try again.',
41
+ };
42
+ }
43
+ },
44
+ });
@@ -0,0 +1,65 @@
1
+ import {
2
+ AuthenticationType,
3
+ httpClient,
4
+ HttpMethod,
5
+ HttpRequest,
6
+ } from '@agnocon/pieces-common';
7
+ import { bexioCommon } from './index';
8
+
9
+ export class BexioClient {
10
+ constructor(private auth: {access_token: string}) {}
11
+
12
+ async makeRequest<T>(
13
+ method: HttpMethod,
14
+ endpoint: string,
15
+ data?: unknown,
16
+ queryParams?: Record<string, string>
17
+ ): Promise<T> {
18
+ // If endpoint already includes version (starts with /2.0/ or /3.0/), use it directly
19
+ // Otherwise, prepend the default API version
20
+ const url = endpoint.startsWith('/2.0/') || endpoint.startsWith('/3.0/')
21
+ ? `${bexioCommon.baseUrl}${endpoint}`
22
+ : `${bexioCommon.baseUrl}/${bexioCommon.api_version}${endpoint}`;
23
+
24
+ const request: HttpRequest = {
25
+ method,
26
+ url,
27
+ authentication: {
28
+ type: AuthenticationType.BEARER_TOKEN,
29
+ token: this.auth.access_token,
30
+ },
31
+ headers: {
32
+ Accept: 'application/json',
33
+ 'Content-Type': 'application/json',
34
+ },
35
+ };
36
+
37
+ if (data) {
38
+ request.body = data;
39
+ }
40
+
41
+ if (queryParams) {
42
+ request.queryParams = queryParams;
43
+ }
44
+
45
+ const response = await httpClient.sendRequest<T>(request);
46
+ return response.body;
47
+ }
48
+
49
+ async get<T>(endpoint: string, queryParams?: Record<string, string>): Promise<T> {
50
+ return this.makeRequest<T>(HttpMethod.GET, endpoint, undefined, queryParams);
51
+ }
52
+
53
+ async post<T>(endpoint: string, data: unknown, queryParams?: Record<string, string>): Promise<T> {
54
+ return this.makeRequest<T>(HttpMethod.POST, endpoint, data, queryParams);
55
+ }
56
+
57
+ async patch<T>(endpoint: string, data: unknown): Promise<T> {
58
+ return this.makeRequest<T>(HttpMethod.PATCH, endpoint, data);
59
+ }
60
+
61
+ async delete<T>(endpoint: string): Promise<T> {
62
+ return this.makeRequest<T>(HttpMethod.DELETE, endpoint);
63
+ }
64
+ }
65
+
@@ -0,0 +1,5 @@
1
+ export const bexioCommon = {
2
+ baseUrl: 'https://api.bexio.com',
3
+ api_version: '3.0',
4
+ };
5
+