@genz-its/sevdesk-cli 0.0.0 → 0.1.1

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
@@ -88,6 +88,9 @@ sevdesk transactions:list --unbooked --json | jq -r '.[].id'
88
88
  - [`accounts:create-file-import`](#accountscreate-file-import)
89
89
  - [`accounts:get`](#accountsget)
90
90
  - [`accounts:list`](#accountslist)
91
+ - [`contacts:add-address`](#contactsadd-address)
92
+ - [`contacts:add-email`](#contactsadd-email)
93
+ - [`contacts:add-phone`](#contactsadd-phone)
91
94
  - [`contacts:create`](#contactscreate)
92
95
  - [`contacts:delete`](#contactsdelete)
93
96
  - [`contacts:get`](#contactsget)
@@ -121,6 +124,7 @@ sevdesk transactions:list --unbooked --json | jq -r '.[].id'
121
124
  - [`vouchers:enshrine`](#vouchersenshrine)
122
125
  - [`vouchers:get`](#vouchersget)
123
126
  - [`vouchers:list`](#voucherslist)
127
+ - [`vouchers:positions`](#voucherspositions)
124
128
  - [`vouchers:reset-to-draft`](#vouchersreset-to-draft)
125
129
  - [`vouchers:reset-to-open`](#vouchersreset-to-open)
126
130
 
@@ -227,6 +231,56 @@ sevdesk accounts:list [options]
227
231
  - `--offset`: The number of check accounts to skip.
228
232
  - `--json`: Output in JSON format.
229
233
 
234
+ ### `contacts:add-address`
235
+
236
+ Add an address to a contact.
237
+
238
+ ```bash
239
+ sevdesk contacts:add-address [options]
240
+ ```
241
+
242
+ **Options:**
243
+
244
+ - `--contact`: The contact ID. If omitted, you will be prompted.
245
+ - `--street`: Street and house number.
246
+ - `--zip`: Zip code.
247
+ - `--city`: City name.
248
+ - `--country`: ID of the country as a StaticCountry ID, for example `1` for Germany. There is no lookup endpoint in this CLI, but an existing address of a contact reveals the IDs of other countries. If omitted, you will be prompted.
249
+ - `--category`: ID of the address category. The sevdesk API does not document the IDs, they are listed by a `GET` to `/Category?objectType=ContactAddress` and an existing address of a contact reveals the ones in use. If omitted, you will be prompted.
250
+ - `--json`: Output in JSON format.
251
+
252
+ ### `contacts:add-email`
253
+
254
+ Add an e-mail address to a contact.
255
+
256
+ ```bash
257
+ sevdesk contacts:add-email [options]
258
+ ```
259
+
260
+ **Options:**
261
+
262
+ - `--contact`: The contact ID. If omitted, you will be prompted.
263
+ - `--email`: The e-mail address. If omitted, you will be prompted.
264
+ - `--key`: ID of the communication way key: `1` private, `2` work, `7` newsletter, `8` invoicing. Defaults to `2`.
265
+ - `--main`: Mark the e-mail address as the main one of the contact. Defaults to `false`.
266
+ - `--json`: Output in JSON format.
267
+
268
+ ### `contacts:add-phone`
269
+
270
+ Add a phone number to a contact.
271
+
272
+ ```bash
273
+ sevdesk contacts:add-phone [options]
274
+ ```
275
+
276
+ **Options:**
277
+
278
+ - `--contact`: The contact ID. If omitted, you will be prompted.
279
+ - `--phone`: The phone number. If omitted, you will be prompted.
280
+ - `--key`: ID of the communication way key: `1` private, `2` work, `3` fax, `4` mobile. Defaults to `2`.
281
+ - `--main`: Mark the phone number as the main one of the contact. Defaults to `false`.
282
+ - `--json`: Output in JSON format.
283
+
230
284
  ### `contacts:create`
231
285
 
232
286
  Create a contact. Use `--name` for organizations and `--surename` together with `--familyname` for persons.
@@ -263,7 +317,7 @@ sevdesk contacts:delete [options]
263
317
 
264
318
  ### `contacts:get`
265
319
 
266
- Show a single contact.
320
+ Show a single contact with its addresses and communication ways.
267
321
 
268
322
  ```bash
269
323
  sevdesk contacts:get [options]
@@ -272,7 +326,7 @@ sevdesk contacts:get [options]
272
326
  **Options:**
273
327
 
274
328
  - `--id`: The contact ID. If omitted, you will be prompted.
275
- - `--json`: Output in JSON format.
329
+ - `--json`: Output in JSON format. Prints an object with the keys `contact`, `addresses` and `communicationWays`.
276
330
 
277
331
  ### `contacts:list`
278
332
 
@@ -286,6 +340,8 @@ sevdesk contacts:list [options]
286
340
 
287
341
  - `--name`: Filter by organization, first or last name.
288
342
  - `--customer-number`: Filter by customer number.
343
+ - `--depth`: Contact depth: `0` returns only organizations, `1` organizations and persons. Defaults to `0`.
344
+ - `--category`: ID of the contact category to filter by: `2` supplier, `3` customer, `4` partner.
289
345
  - `--limit`: Maximum number of contacts to return.
290
346
  - `--offset`: Number of contacts to skip.
291
347
  - `--json`: Output in JSON format.
@@ -765,6 +821,21 @@ sevdesk vouchers:list [options]
765
821
  - `--offset`: Number of vouchers to skip.
766
822
  - `--json`: Output in JSON format.
767
823
 
824
+ ### `vouchers:positions`
825
+
826
+ List voucher positions.
827
+
828
+ ```bash
829
+ sevdesk vouchers:positions [options]
830
+ ```
831
+
832
+ **Options:**
833
+
834
+ - `--voucher`: ID of the voucher whose positions to list.
835
+ - `--limit`: Maximum number of positions to return.
836
+ - `--offset`: Number of positions to skip.
837
+ - `--json`: Output in JSON format.
838
+
768
839
  ### `vouchers:reset-to-draft`
769
840
 
770
841
  Reset a voucher to the draft status. This unlinks existing payments.
@@ -795,6 +866,6 @@ sevdesk vouchers:reset-to-open [options]
795
866
 
796
867
  ## License
797
868
 
798
- [MIT](../../LICENSE)
869
+ See [LICENSE](https://github.com/genz-its/sevdesk/blob/main/LICENSE).
799
870
 
800
871
  [^1]: This project is not affiliated with, endorsed by, sponsored by, or approved by sevDesk GmbH or any of their affiliates or subsidiaries.
package/dist/index.js CHANGED
@@ -142,6 +142,12 @@ function requireInteractive(requirement) {
142
142
  }
143
143
  //#endregion
144
144
  //#region src/output.ts
145
+ /** Formats a contact reference as its organization or person name. */
146
+ function contactLabel(ref) {
147
+ if (!ref) return "-";
148
+ const personName = [ref.surename, ref.familyname].filter((part) => part).join(" ");
149
+ return ref.name || personName || ref.id || "-";
150
+ }
145
151
  function printJson(value) {
146
152
  console.log(JSON.stringify(value, null, 2));
147
153
  }
@@ -308,6 +314,129 @@ var list_default$8 = defineCommand({
308
314
  }
309
315
  });
310
316
  //#endregion
317
+ //#region src/commands/contacts/add-address.ts
318
+ var add_address_default = defineCommand({
319
+ description: "Add an address to a contact.",
320
+ options: defineOptions(z.object({
321
+ contact: z.coerce.number().optional().describe("The contact ID. If omitted, you will be prompted."),
322
+ street: z.string().optional().describe("Street and house number."),
323
+ zip: z.string().optional().describe("Zip code."),
324
+ city: z.string().optional().describe("City name."),
325
+ country: z.coerce.number().optional().describe("ID of the country as a StaticCountry ID, for example 1 for Germany. There is no lookup endpoint in this CLI, but an existing address of a contact reveals the IDs of other countries. If omitted, you will be prompted."),
326
+ category: z.coerce.number().optional().describe("ID of the address category. The sevdesk API does not document the IDs, they are listed by a GET to /Category?objectType=ContactAddress and an existing address of a contact reveals the ones in use. If omitted, you will be prompted."),
327
+ json: z.boolean().default(false).describe("Output in JSON format.")
328
+ })),
329
+ action: async (options) => {
330
+ const client = await requireClient();
331
+ const contactId = await requireNumberOption({
332
+ value: options.contact,
333
+ requirement: "a contact ID via --contact",
334
+ question: "Enter the contact ID:"
335
+ });
336
+ const countryId = await requireNumberOption({
337
+ value: options.country,
338
+ requirement: "a country ID via --country",
339
+ question: "Enter the country ID, for example 1 for Germany:"
340
+ });
341
+ const categoryId = await requireNumberOption({
342
+ value: options.category,
343
+ requirement: "an address category ID via --category",
344
+ question: "Enter the address category ID:"
345
+ });
346
+ const address = await client.contactAddresses.create({
347
+ contactId,
348
+ countryId,
349
+ categoryId,
350
+ street: options.street,
351
+ zip: options.zip,
352
+ city: options.city
353
+ });
354
+ if (options.json) {
355
+ printJson(address);
356
+ return;
357
+ }
358
+ consola.success(`Created contact address ${address.id}.`);
359
+ }
360
+ });
361
+ //#endregion
362
+ //#region src/commands/contacts/add-email.ts
363
+ var add_email_default = defineCommand({
364
+ description: "Add an e-mail address to a contact.",
365
+ options: defineOptions(z.object({
366
+ contact: z.coerce.number().optional().describe("The contact ID. If omitted, you will be prompted."),
367
+ email: z.string().optional().describe("The e-mail address. If omitted, you will be prompted."),
368
+ key: z.coerce.number().default(2).describe("ID of the communication way key: 1 private, 2 work, 7 newsletter, 8 invoicing."),
369
+ main: z.boolean().default(false).describe("Mark the e-mail address as the main one of the contact."),
370
+ json: z.boolean().default(false).describe("Output in JSON format.")
371
+ })),
372
+ action: async (options) => {
373
+ const client = await requireClient();
374
+ const contactId = await requireNumberOption({
375
+ value: options.contact,
376
+ requirement: "a contact ID via --contact",
377
+ question: "Enter the contact ID:"
378
+ });
379
+ const email = await requireStringOption({
380
+ value: options.email,
381
+ requirement: "an e-mail address via --email",
382
+ question: "Enter the e-mail address:"
383
+ });
384
+ if (!email.includes("@")) {
385
+ consola.error("The e-mail address must contain an \"@\".");
386
+ process.exit(1);
387
+ }
388
+ const communicationWay = await client.communicationWays.create({
389
+ contactId,
390
+ type: "EMAIL",
391
+ value: email,
392
+ keyId: options.key,
393
+ main: options.main
394
+ });
395
+ if (options.json) {
396
+ printJson(communicationWay);
397
+ return;
398
+ }
399
+ consola.success(`Created e-mail communication way ${communicationWay.id}.`);
400
+ }
401
+ });
402
+ //#endregion
403
+ //#region src/commands/contacts/add-phone.ts
404
+ var add_phone_default = defineCommand({
405
+ description: "Add a phone number to a contact.",
406
+ options: defineOptions(z.object({
407
+ contact: z.coerce.number().optional().describe("The contact ID. If omitted, you will be prompted."),
408
+ phone: z.string().optional().describe("The phone number. If omitted, you will be prompted."),
409
+ key: z.coerce.number().default(2).describe("ID of the communication way key: 1 private, 2 work, 3 fax, 4 mobile."),
410
+ main: z.boolean().default(false).describe("Mark the phone number as the main one of the contact."),
411
+ json: z.boolean().default(false).describe("Output in JSON format.")
412
+ })),
413
+ action: async (options) => {
414
+ const client = await requireClient();
415
+ const contactId = await requireNumberOption({
416
+ value: options.contact,
417
+ requirement: "a contact ID via --contact",
418
+ question: "Enter the contact ID:"
419
+ });
420
+ const phone = await requireStringOption({
421
+ value: options.phone,
422
+ requirement: "a phone number via --phone",
423
+ question: "Enter the phone number:"
424
+ });
425
+ const communicationWay = await client.communicationWays.create({
426
+ contactId,
427
+ type: "PHONE",
428
+ value: phone,
429
+ keyId: options.key,
430
+ main: options.main
431
+ });
432
+ if (options.json) {
433
+ printJson(communicationWay);
434
+ return;
435
+ }
436
+ consola.success(`Created phone communication way ${communicationWay.id}.`);
437
+ }
438
+ });
439
+ //#endregion
311
440
  //#region src/commands/contacts/create.ts
312
441
  var create_default$3 = defineCommand({
313
442
  description: "Create a contact.",
@@ -377,8 +506,10 @@ var delete_default$1 = defineCommand({
377
506
  });
378
507
  //#endregion
379
508
  //#region src/commands/contacts/get.ts
509
+ /** The `/ContactAddress` endpoint cannot filter by contact, so we filter here. */
510
+ const ADDRESS_LOOKUP_LIMIT = 100;
380
511
  var get_default$6 = defineCommand({
381
- description: "Show a single contact.",
512
+ description: "Show a single contact with its addresses and communication ways.",
382
513
  options: defineOptions(z.object({
383
514
  id: z.coerce.number().optional().describe("The contact ID. If omitted, you will be prompted."),
384
515
  json: z.boolean().default(false).describe("Output in JSON format.")
@@ -391,8 +522,14 @@ var get_default$6 = defineCommand({
391
522
  question: "Enter the contact ID:"
392
523
  });
393
524
  const contact = await client.contacts.get({ contactId });
525
+ const addresses = (await client.contactAddresses.list({ limit: ADDRESS_LOOKUP_LIMIT })).filter((address) => address.contact.id === String(contactId));
526
+ const communicationWays = await client.communicationWays.list({ contactId });
394
527
  if (options.json) {
395
- printJson(contact);
528
+ printJson({
529
+ contact,
530
+ addresses,
531
+ communicationWays
532
+ });
396
533
  return;
397
534
  }
398
535
  consola.info(`ID: ${contact.id}`);
@@ -405,8 +542,25 @@ var get_default$6 = defineCommand({
405
542
  consola.info(`Description: ${contact.description ?? "-"}`);
406
543
  consola.info(`VAT number: ${contact.vatNumber ?? "-"}`);
407
544
  consola.info(`Tax number: ${contact.taxNumber ?? "-"}`);
545
+ printSection("Addresses:", addresses.map(formatAddress));
546
+ printSection("Communication ways:", communicationWays.map(formatCommunicationWay));
408
547
  }
409
548
  });
549
+ function printSection(title, lines) {
550
+ consola.info(title);
551
+ for (const line of lines.length === 0 ? ["-"] : lines) consola.info(` ${line}`);
552
+ }
553
+ function formatAddress(address) {
554
+ return [
555
+ address.street,
556
+ [address.zip, address.city].filter((part) => part).join(" "),
557
+ `country ${address.country.id}`
558
+ ].filter((part) => part).join(", ");
559
+ }
560
+ function formatCommunicationWay(communicationWay) {
561
+ const main = communicationWay.main === "1" ? " (main)" : "";
562
+ return `${communicationWay.type}: ${communicationWay.value}${main}`;
563
+ }
410
564
  //#endregion
411
565
  //#region src/commands/contacts/list.ts
412
566
  var list_default$7 = defineCommand({
@@ -414,6 +568,8 @@ var list_default$7 = defineCommand({
414
568
  options: defineOptions(z.object({
415
569
  name: z.string().optional().describe("Filter by organization, first or last name."),
416
570
  customerNumber: z.string().optional().describe("Filter by customer number."),
571
+ depth: z.coerce.number().optional().describe("Contact depth: 0 returns only organizations, 1 organizations and persons. Defaults to 0."),
572
+ category: z.coerce.number().optional().describe("ID of the contact category to filter by: 2 supplier, 3 customer, 4 partner."),
417
573
  limit: z.coerce.number().optional().describe("Maximum number of contacts to return."),
418
574
  offset: z.coerce.number().optional().describe("Number of contacts to skip."),
419
575
  json: z.boolean().default(false).describe("Output in JSON format.")
@@ -422,6 +578,8 @@ var list_default$7 = defineCommand({
422
578
  const contacts = await (await requireClient()).contacts.list({
423
579
  name: options.name,
424
580
  customerNumber: options.customerNumber,
581
+ depth: toDepth(options.depth),
582
+ categoryId: options.category,
425
583
  limit: options.limit,
426
584
  offset: options.offset
427
585
  });
@@ -442,6 +600,10 @@ var list_default$7 = defineCommand({
442
600
  })));
443
601
  }
444
602
  });
603
+ function toDepth(depth) {
604
+ if (depth === void 0) return;
605
+ return depth === 0 ? "0" : "1";
606
+ }
445
607
  function formatContactName(contact) {
446
608
  return contact.name ?? [contact.surename, contact.familyname].filter(Boolean).join(" ");
447
609
  }
@@ -501,7 +663,10 @@ var get_default$5 = defineCommand({
501
663
  requirement: "a credit note ID via --id",
502
664
  question: "Enter the credit note ID:"
503
665
  });
504
- const creditNote = await client.creditNotes.get({ creditNoteId });
666
+ const creditNote = await client.creditNotes.get({
667
+ creditNoteId,
668
+ embed: ["contact"]
669
+ });
505
670
  if (options.json) {
506
671
  printJson(creditNote);
507
672
  return;
@@ -510,7 +675,7 @@ var get_default$5 = defineCommand({
510
675
  consola.info(`Number: ${creditNote.creditNoteNumber ?? "-"}`);
511
676
  consola.info(`Date: ${creditNote.creditNoteDate}`);
512
677
  consola.info(`Status: ${creditNote.status}`);
513
- consola.info(`Contact: ${creditNote.contact?.id ?? "-"}`);
678
+ consola.info(`Contact: ${contactLabel(creditNote.contact)}`);
514
679
  consola.info(`Net: ${creditNote.sumNet}`);
515
680
  consola.info(`Tax: ${creditNote.sumTax}`);
516
681
  consola.info(`Gross: ${creditNote.sumGross}`);
@@ -539,7 +704,8 @@ var list_default$6 = defineCommand({
539
704
  endDate: options.endDate,
540
705
  contactId: options.contact,
541
706
  limit: options.limit,
542
- offset: options.offset
707
+ offset: options.offset,
708
+ embed: ["contact"]
543
709
  });
544
710
  if (options.json) {
545
711
  printJson(creditNotes);
@@ -553,7 +719,7 @@ var list_default$6 = defineCommand({
553
719
  id: creditNote.id,
554
720
  number: creditNote.creditNoteNumber ?? "",
555
721
  date: creditNote.creditNoteDate,
556
- contact: creditNote.contact?.id ?? "",
722
+ contact: contactLabel(creditNote.contact),
557
723
  gross: creditNote.sumGross,
558
724
  status: creditNote.status
559
725
  })));
@@ -884,7 +1050,10 @@ var get_default$4 = defineCommand({
884
1050
  requirement: "an invoice ID via --id",
885
1051
  question: "Enter the invoice ID:"
886
1052
  });
887
- const invoice = await client.invoices.get({ invoiceId });
1053
+ const invoice = await client.invoices.get({
1054
+ invoiceId,
1055
+ embed: ["contact"]
1056
+ });
888
1057
  if (options.json) {
889
1058
  printJson(invoice);
890
1059
  return;
@@ -893,7 +1062,7 @@ var get_default$4 = defineCommand({
893
1062
  consola.info(`Number: ${invoice.invoiceNumber ?? "-"}`);
894
1063
  consola.info(`Date: ${invoice.invoiceDate}`);
895
1064
  consola.info(`Status: ${invoice.status}`);
896
- consola.info(`Contact: ${invoice.contact?.id ?? "-"}`);
1065
+ consola.info(`Contact: ${contactLabel(invoice.contact)}`);
897
1066
  consola.info(`Net: ${invoice.sumNet}`);
898
1067
  consola.info(`Tax: ${invoice.sumTax}`);
899
1068
  consola.info(`Gross: ${invoice.sumGross}`);
@@ -922,7 +1091,8 @@ var list_default$5 = defineCommand({
922
1091
  endDate: options.endDate,
923
1092
  contactId: options.contact,
924
1093
  limit: options.limit,
925
- offset: options.offset
1094
+ offset: options.offset,
1095
+ embed: ["contact"]
926
1096
  });
927
1097
  if (options.json) {
928
1098
  printJson(invoices);
@@ -936,7 +1106,7 @@ var list_default$5 = defineCommand({
936
1106
  id: invoice.id,
937
1107
  number: invoice.invoiceNumber ?? "",
938
1108
  date: invoice.invoiceDate,
939
- contact: invoice.contact?.id ?? "",
1109
+ contact: contactLabel(invoice.contact),
940
1110
  gross: invoice.sumGross,
941
1111
  status: invoice.status
942
1112
  })));
@@ -1030,7 +1200,10 @@ var get_default$3 = defineCommand({
1030
1200
  requirement: "an order ID via --id",
1031
1201
  question: "Enter the order ID:"
1032
1202
  });
1033
- const order = await client.orders.get({ orderId });
1203
+ const order = await client.orders.get({
1204
+ orderId,
1205
+ embed: ["contact"]
1206
+ });
1034
1207
  if (options.json) {
1035
1208
  printJson(order);
1036
1209
  return;
@@ -1039,7 +1212,7 @@ var get_default$3 = defineCommand({
1039
1212
  consola.info(`Number: ${order.orderNumber}`);
1040
1213
  consola.info(`Date: ${order.orderDate}`);
1041
1214
  consola.info(`Status: ${order.status}`);
1042
- consola.info(`Contact: ${order.contact?.id ?? "-"}`);
1215
+ consola.info(`Contact: ${contactLabel(order.contact)}`);
1043
1216
  consola.info(`Net: ${order.sumNet}`);
1044
1217
  consola.info(`Tax: ${order.sumTax}`);
1045
1218
  consola.info(`Gross: ${order.sumGross}`);
@@ -1068,7 +1241,8 @@ var list_default$4 = defineCommand({
1068
1241
  endDate: options.endDate,
1069
1242
  contactId: options.contact,
1070
1243
  limit: options.limit,
1071
- offset: options.offset
1244
+ offset: options.offset,
1245
+ embed: ["contact"]
1072
1246
  });
1073
1247
  if (options.json) {
1074
1248
  printJson(orders);
@@ -1082,7 +1256,7 @@ var list_default$4 = defineCommand({
1082
1256
  id: order.id,
1083
1257
  number: order.orderNumber,
1084
1258
  date: order.orderDate,
1085
- contact: order.contact?.id ?? "",
1259
+ contact: contactLabel(order.contact),
1086
1260
  gross: order.sumGross,
1087
1261
  status: order.status
1088
1262
  })));
@@ -1608,7 +1782,10 @@ var get_default = defineCommand({
1608
1782
  requirement: "a voucher ID via --id",
1609
1783
  question: "Enter the voucher ID:"
1610
1784
  });
1611
- const voucher = await client.vouchers.get({ voucherId });
1785
+ const voucher = await client.vouchers.get({
1786
+ voucherId,
1787
+ embed: ["supplier"]
1788
+ });
1612
1789
  if (options.json) {
1613
1790
  printJson(voucher);
1614
1791
  return;
@@ -1616,7 +1793,7 @@ var get_default = defineCommand({
1616
1793
  consola.info(`ID: ${voucher.id}`);
1617
1794
  consola.info(`Status: ${voucher.status ?? "-"}`);
1618
1795
  consola.info(`Date: ${voucher.voucherDate ?? "-"}`);
1619
- consola.info(`Supplier: ${voucher.supplierName ?? voucher.supplier?.id ?? "-"}`);
1796
+ consola.info(`Supplier: ${voucher.supplierName ?? contactLabel(voucher.supplier)}`);
1620
1797
  consola.info(`Description: ${voucher.description ?? "-"}`);
1621
1798
  consola.info(`Net: ${voucher.sumNet}`);
1622
1799
  consola.info(`Tax: ${voucher.sumTax}`);
@@ -1649,7 +1826,8 @@ var list_default = defineCommand({
1649
1826
  endDate: options.endDate,
1650
1827
  contactId: options.contact,
1651
1828
  limit: options.limit,
1652
- offset: options.offset
1829
+ offset: options.offset,
1830
+ embed: ["supplier"]
1653
1831
  });
1654
1832
  if (options.json) {
1655
1833
  printJson(vouchers);
@@ -1662,7 +1840,7 @@ var list_default = defineCommand({
1662
1840
  printTable(vouchers.map((voucher) => ({
1663
1841
  id: voucher.id,
1664
1842
  date: voucher.voucherDate ?? "",
1665
- supplier: voucher.supplierName ?? voucher.supplier?.id ?? "",
1843
+ supplier: voucher.supplierName ?? contactLabel(voucher.supplier),
1666
1844
  description: voucher.description ?? "",
1667
1845
  gross: voucher.sumGross,
1668
1846
  status: voucher.status ?? ""
@@ -1670,6 +1848,46 @@ var list_default = defineCommand({
1670
1848
  }
1671
1849
  });
1672
1850
  //#endregion
1851
+ //#region src/commands/vouchers/positions.ts
1852
+ var positions_default = defineCommand({
1853
+ description: "List voucher positions.",
1854
+ options: defineOptions(z.object({
1855
+ voucher: z.coerce.number().optional().describe("ID of the voucher whose positions to list."),
1856
+ limit: z.coerce.number().optional().describe("Maximum number of positions to return."),
1857
+ offset: z.coerce.number().optional().describe("Number of positions to skip."),
1858
+ json: z.boolean().default(false).describe("Output in JSON format.")
1859
+ })),
1860
+ action: async (options) => {
1861
+ const positions = await (await requireClient()).vouchers.listPositions({
1862
+ voucherId: options.voucher,
1863
+ limit: options.limit,
1864
+ offset: options.offset,
1865
+ embed: ["accountDatev"]
1866
+ });
1867
+ if (options.json) {
1868
+ printJson(positions);
1869
+ return;
1870
+ }
1871
+ if (positions.length === 0) {
1872
+ consola.info("No voucher positions found.");
1873
+ return;
1874
+ }
1875
+ printTable(positions.map((position) => ({
1876
+ id: position.id,
1877
+ voucher: position.voucher.id,
1878
+ account: accountLabel(position.accountDatev),
1879
+ taxRate: position.taxRate,
1880
+ net: String(position.net),
1881
+ sumNet: position.sumNet,
1882
+ sumGross: position.sumGross
1883
+ })));
1884
+ }
1885
+ });
1886
+ function accountLabel(account) {
1887
+ const parts = [account.number ?? account.accountNumber, account.name ?? account.accountName].filter((part) => part !== void 0 && part !== null && part !== "");
1888
+ return parts.length === 0 ? account.id : parts.join(" ");
1889
+ }
1890
+ //#endregion
1673
1891
  //#region src/commands/vouchers/reset-to-draft.ts
1674
1892
  var reset_to_draft_default = defineCommand({
1675
1893
  description: "Reset a voucher to the draft status.",
@@ -1744,6 +1962,9 @@ const config = defineConfig({
1744
1962
  "accounts:create-file-import": create_file_import_default,
1745
1963
  "accounts:get": get_default$7,
1746
1964
  "accounts:list": list_default$8,
1965
+ "contacts:add-address": add_address_default,
1966
+ "contacts:add-email": add_email_default,
1967
+ "contacts:add-phone": add_phone_default,
1747
1968
  "contacts:create": create_default$3,
1748
1969
  "contacts:delete": delete_default$1,
1749
1970
  "contacts:get": get_default$6,
@@ -1777,6 +1998,7 @@ const config = defineConfig({
1777
1998
  "vouchers:enshrine": enshrine_default,
1778
1999
  "vouchers:get": get_default,
1779
2000
  "vouchers:list": list_default,
2001
+ "vouchers:positions": positions_default,
1780
2002
  "vouchers:reset-to-draft": reset_to_draft_default,
1781
2003
  "vouchers:reset-to-open": reset_to_open_default
1782
2004
  }