@genz-its/sevdesk-cli 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -148,6 +148,17 @@ function contactLabel(ref) {
148
148
  const personName = [ref.surename, ref.familyname].filter((part) => part).join(" ");
149
149
  return ref.name || personName || ref.id || "-";
150
150
  }
151
+ /**
152
+ * Formats a service period (Leistungszeitraum) as plain dates, collapsing to a
153
+ * single date when there is no end. The API returns local datetimes, so the
154
+ * date part is sliced off instead of parsed, which would shift the day across
155
+ * the UTC boundary.
156
+ */
157
+ function servicePeriodLabel(from, until) {
158
+ if (!from) return "";
159
+ const start = from.slice(0, 10);
160
+ return until ? `${start} – ${until.slice(0, 10)}` : start;
161
+ }
151
162
  function printJson(value) {
152
163
  console.log(JSON.stringify(value, null, 2));
153
164
  }
@@ -190,40 +201,60 @@ var get_default$8 = defineCommand({
190
201
  }
191
202
  });
192
203
  //#endregion
193
- //#region src/commands/accounts-datev/list.ts
204
+ //#region src/pagination.ts
205
+ /**
206
+ * Rows requested per page. The sevdesk API defaults to 100 when no `limit` is
207
+ * sent, which is why an unpaginated list silently stops at 100 rows.
208
+ */
194
209
  const PAGE_SIZE = 1e3;
210
+ /**
211
+ * Collects rows of a list endpoint across as many pages as needed.
212
+ *
213
+ * Paging stops on an empty page rather than a short one, so a server-side cap
214
+ * on `limit` cannot truncate the result the way the API default does.
215
+ */
216
+ async function fetchAll(fetchPage, options = {}) {
217
+ const { limit, keep } = options;
218
+ const items = [];
219
+ let offset = options.offset ?? 0;
220
+ while (limit === void 0 || items.length < limit) {
221
+ const page = await fetchPage({
222
+ limit: pageSize(limit, items.length, keep),
223
+ offset
224
+ });
225
+ if (page.length === 0) break;
226
+ offset += page.length;
227
+ items.push(...keep === void 0 ? page : page.filter(keep));
228
+ }
229
+ return limit === void 0 ? items : items.slice(0, limit);
230
+ }
231
+ /**
232
+ * Without a `keep` filter every row counts towards `limit`, so a small `limit`
233
+ * only needs a correspondingly small page.
234
+ */
235
+ function pageSize(limit, collected, keep) {
236
+ if (limit === void 0 || keep !== void 0) return PAGE_SIZE;
237
+ return Math.min(limit - collected, PAGE_SIZE);
238
+ }
239
+ //#endregion
240
+ //#region src/commands/accounts-datev/list.ts
195
241
  var list_default$9 = defineCommand({
196
242
  description: "List booking accounts (AccountDatev). Covers only accounts visible in the sevdesk account picker; hidden accounts (for example some tax accounts) are reachable via accounts-datev:get. Backed by an undocumented sevdesk endpoint that may change without notice.",
197
243
  options: defineOptions(z.object({
198
244
  number: z.string().optional().describe("Only show accounts with this account number. Filtered client-side across all visible accounts."),
199
245
  nameLike: z.string().optional().describe("Only show accounts whose name contains this text. Filtered client-side across all visible accounts."),
200
- limit: z.coerce.number().optional().describe("Maximum number of accounts to return."),
201
- offset: z.coerce.number().optional().describe("Number of accounts to skip. Ignored when a filter is used."),
246
+ limit: z.coerce.number().optional().describe("Maximum number of accounts to return. Defaults to all of them."),
247
+ offset: z.coerce.number().optional().describe("Number of accounts to skip before filtering."),
202
248
  json: z.boolean().default(false).describe("Output in JSON format.")
203
249
  })),
204
250
  action: async (options) => {
205
251
  const client = await requireClient();
206
- const filtering = options.number !== void 0 || options.nameLike !== void 0;
207
- let accounts;
208
- if (filtering) {
209
- accounts = [];
210
- for (let offset = 0;; offset += PAGE_SIZE) {
211
- const page = await client.accountsDatev.list({
212
- limit: PAGE_SIZE,
213
- offset
214
- });
215
- accounts.push(...page);
216
- if (page.length < PAGE_SIZE) break;
217
- }
218
- if (options.number !== void 0) accounts = accounts.filter((account) => account.number === options.number);
219
- if (options.nameLike !== void 0) {
220
- const needle = options.nameLike.toLowerCase();
221
- accounts = accounts.filter((account) => (account.name ?? "").toLowerCase().includes(needle));
222
- }
223
- if (options.limit !== void 0) accounts = accounts.slice(0, options.limit);
224
- } else accounts = await client.accountsDatev.list({
252
+ const needle = options.nameLike?.toLowerCase();
253
+ const filtering = options.number !== void 0 || needle !== void 0;
254
+ const accounts = await fetchAll((page) => client.accountsDatev.list(page), {
225
255
  limit: options.limit,
226
- offset: options.offset
256
+ offset: options.offset,
257
+ keep: filtering ? (account) => (options.number === void 0 || account.number === options.number) && (needle === void 0 || (account.name ?? "").toLowerCase().includes(needle)) : void 0
227
258
  });
228
259
  if (options.json) {
229
260
  printJson(accounts);
@@ -368,12 +399,13 @@ var get_default$7 = defineCommand({
368
399
  var list_default$8 = defineCommand({
369
400
  description: "List your check accounts.",
370
401
  options: defineOptions(z.object({
371
- limit: z.coerce.number().optional().describe("The maximum number of check accounts to return."),
402
+ limit: z.coerce.number().optional().describe("The maximum number of check accounts to return. Defaults to all of them."),
372
403
  offset: z.coerce.number().optional().describe("The number of check accounts to skip."),
373
404
  json: z.boolean().default(false).describe("Output in JSON format.")
374
405
  })),
375
406
  action: async (options) => {
376
- const checkAccounts = await (await requireClient()).checkAccounts.list({
407
+ const client = await requireClient();
408
+ const checkAccounts = await fetchAll((page) => client.checkAccounts.list(page), {
377
409
  limit: options.limit,
378
410
  offset: options.offset
379
411
  });
@@ -588,9 +620,36 @@ var delete_default$1 = defineCommand({
588
620
  }
589
621
  });
590
622
  //#endregion
623
+ //#region src/commands/contacts/delete-address.ts
624
+ var delete_address_default = defineCommand({
625
+ description: "Delete an address of a contact.",
626
+ options: defineOptions(z.object({
627
+ id: z.coerce.number().optional().describe("The contact address ID, as shown by contacts:get. If omitted, you will be prompted."),
628
+ yes: z.boolean().default(false).describe("Skip the confirmation prompt."),
629
+ json: z.boolean().default(false).describe("Output in JSON format.")
630
+ })),
631
+ action: async (options) => {
632
+ const client = await requireClient();
633
+ const contactAddressId = await requireNumberOption({
634
+ value: options.id,
635
+ requirement: "a contact address ID via --id",
636
+ question: "Enter the contact address ID:"
637
+ });
638
+ if (!await confirmOrAbort({
639
+ message: `Delete contact address ${contactAddressId}?`,
640
+ yes: options.yes,
641
+ initial: false
642
+ })) return;
643
+ await client.contactAddresses.delete({ contactAddressId });
644
+ if (options.json) {
645
+ printJson({ deleted: true });
646
+ return;
647
+ }
648
+ consola.success("Contact address deleted.");
649
+ }
650
+ });
651
+ //#endregion
591
652
  //#region src/commands/contacts/get.ts
592
- /** The `/ContactAddress` endpoint cannot filter by contact, so we filter here. */
593
- const ADDRESS_LOOKUP_LIMIT = 100;
594
653
  var get_default$6 = defineCommand({
595
654
  description: "Show a single contact with its addresses and communication ways.",
596
655
  options: defineOptions(z.object({
@@ -605,8 +664,12 @@ var get_default$6 = defineCommand({
605
664
  question: "Enter the contact ID:"
606
665
  });
607
666
  const contact = await client.contacts.get({ contactId });
608
- const addresses = (await client.contactAddresses.list({ limit: ADDRESS_LOOKUP_LIMIT })).filter((address) => address.contact.id === String(contactId));
609
- const communicationWays = await client.communicationWays.list({ contactId });
667
+ /** The `/ContactAddress` endpoint cannot filter by contact, so we filter here. */
668
+ const addresses = await fetchAll((page) => client.contactAddresses.list(page), { keep: (address) => address.contact.id === String(contactId) });
669
+ const communicationWays = await fetchAll((page) => client.communicationWays.list({
670
+ contactId,
671
+ ...page
672
+ }));
610
673
  if (options.json) {
611
674
  printJson({
612
675
  contact,
@@ -633,12 +696,14 @@ function printSection(title, lines) {
633
696
  consola.info(title);
634
697
  for (const line of lines.length === 0 ? ["-"] : lines) consola.info(` ${line}`);
635
698
  }
699
+ /** The id is shown because contacts:update-address and contacts:delete-address need it. */
636
700
  function formatAddress(address) {
637
- return [
701
+ const parts = [
638
702
  address.street,
639
703
  [address.zip, address.city].filter((part) => part).join(" "),
640
704
  `country ${address.country.id}`
641
- ].filter((part) => part).join(", ");
705
+ ];
706
+ return `#${address.id} ${parts.filter((part) => part).join(", ")}`;
642
707
  }
643
708
  function formatCommunicationWay(communicationWay) {
644
709
  const main = communicationWay.main === "1" ? " (main)" : "";
@@ -653,16 +718,19 @@ var list_default$7 = defineCommand({
653
718
  customerNumber: z.string().optional().describe("Filter by customer number."),
654
719
  depth: z.coerce.number().optional().describe("Contact depth: 0 returns only organizations, 1 organizations and persons. Defaults to 0."),
655
720
  category: z.coerce.number().optional().describe("ID of the contact category to filter by: 2 supplier, 3 customer, 4 partner."),
656
- limit: z.coerce.number().optional().describe("Maximum number of contacts to return."),
721
+ limit: z.coerce.number().optional().describe("Maximum number of contacts to return. Defaults to all of them."),
657
722
  offset: z.coerce.number().optional().describe("Number of contacts to skip."),
658
723
  json: z.boolean().default(false).describe("Output in JSON format.")
659
724
  })),
660
725
  action: async (options) => {
661
- const contacts = await (await requireClient()).contacts.list({
726
+ const client = await requireClient();
727
+ const contacts = await fetchAll((page) => client.contacts.list({
662
728
  name: options.name,
663
729
  customerNumber: options.customerNumber,
664
730
  depth: toDepth(options.depth),
665
731
  categoryId: options.category,
732
+ ...page
733
+ }), {
666
734
  limit: options.limit,
667
735
  offset: options.offset
668
736
  });
@@ -732,6 +800,48 @@ var update_default = defineCommand({
732
800
  }
733
801
  });
734
802
  //#endregion
803
+ //#region src/commands/contacts/update-address.ts
804
+ var update_address_default = defineCommand({
805
+ description: "Update an address of a contact.",
806
+ options: defineOptions(z.object({
807
+ id: z.coerce.number().optional().describe("The contact address ID, as shown by contacts:get. If omitted, you will be prompted."),
808
+ street: z.string().optional().describe("Street and house number."),
809
+ zip: z.string().optional().describe("Zip code."),
810
+ city: z.string().optional().describe("City name."),
811
+ country: z.coerce.number().optional().describe("ID of the country as a StaticCountry ID, for example 1 for Germany."),
812
+ category: z.coerce.number().optional().describe("ID of the address category."),
813
+ json: z.boolean().default(false).describe("Output in JSON format.")
814
+ })),
815
+ action: async (options) => {
816
+ const fields = {
817
+ street: options.street,
818
+ zip: options.zip,
819
+ city: options.city,
820
+ countryId: options.country,
821
+ categoryId: options.category
822
+ };
823
+ if (Object.values(fields).every((value) => value === void 0)) {
824
+ consola.error("You must provide at least one of --street, --zip, --city, --country or --category.");
825
+ process.exit(1);
826
+ }
827
+ const client = await requireClient();
828
+ const contactAddressId = await requireNumberOption({
829
+ value: options.id,
830
+ requirement: "a contact address ID via --id",
831
+ question: "Enter the contact address ID:"
832
+ });
833
+ const address = await client.contactAddresses.update({
834
+ contactAddressId,
835
+ ...fields
836
+ });
837
+ if (options.json) {
838
+ printJson(address);
839
+ return;
840
+ }
841
+ consola.success(`Updated contact address ${address.id}.`);
842
+ }
843
+ });
844
+ //#endregion
735
845
  //#region src/commands/credit-notes/get.ts
736
846
  var get_default$5 = defineCommand({
737
847
  description: "Show a single credit note.",
@@ -775,20 +885,23 @@ var list_default$6 = defineCommand({
775
885
  startDate: z.string().optional().describe("Only credit notes on or after this date as dd.mm.yyyy or Unix timestamp."),
776
886
  endDate: z.string().optional().describe("Only credit notes on or before this date as dd.mm.yyyy or Unix timestamp."),
777
887
  contact: z.coerce.number().optional().describe("ID of the contact whose credit notes to list."),
778
- limit: z.coerce.number().optional().describe("Maximum number of credit notes to return."),
888
+ limit: z.coerce.number().optional().describe("Maximum number of credit notes to return. Defaults to all of them."),
779
889
  offset: z.coerce.number().optional().describe("Number of credit notes to skip."),
780
890
  json: z.boolean().default(false).describe("Output in JSON format.")
781
891
  })),
782
892
  action: async (options) => {
783
- const creditNotes = await (await requireClient()).creditNotes.list({
893
+ const client = await requireClient();
894
+ const creditNotes = await fetchAll((page) => client.creditNotes.list({
784
895
  status: options.status,
785
896
  creditNoteNumber: options.creditNoteNumber,
786
897
  startDate: options.startDate,
787
898
  endDate: options.endDate,
788
899
  contactId: options.contact,
900
+ embed: ["contact"],
901
+ ...page
902
+ }), {
789
903
  limit: options.limit,
790
- offset: options.offset,
791
- embed: ["contact"]
904
+ offset: options.offset
792
905
  });
793
906
  if (options.json) {
794
907
  printJson(creditNotes);
@@ -1162,20 +1275,23 @@ var list_default$5 = defineCommand({
1162
1275
  startDate: z.string().optional().describe("Only invoices on or after this date as dd.mm.yyyy or Unix timestamp."),
1163
1276
  endDate: z.string().optional().describe("Only invoices on or before this date as dd.mm.yyyy or Unix timestamp."),
1164
1277
  contact: z.coerce.number().optional().describe("ID of the contact whose invoices to list."),
1165
- limit: z.coerce.number().optional().describe("Maximum number of invoices to return."),
1278
+ limit: z.coerce.number().optional().describe("Maximum number of invoices to return. Defaults to all of them."),
1166
1279
  offset: z.coerce.number().optional().describe("Number of invoices to skip."),
1167
1280
  json: z.boolean().default(false).describe("Output in JSON format.")
1168
1281
  })),
1169
1282
  action: async (options) => {
1170
- const invoices = await (await requireClient()).invoices.list({
1283
+ const client = await requireClient();
1284
+ const invoices = await fetchAll((page) => client.invoices.list({
1171
1285
  status: options.status,
1172
1286
  invoiceNumber: options.invoiceNumber,
1173
1287
  startDate: options.startDate,
1174
1288
  endDate: options.endDate,
1175
1289
  contactId: options.contact,
1290
+ embed: ["contact"],
1291
+ ...page
1292
+ }), {
1176
1293
  limit: options.limit,
1177
- offset: options.offset,
1178
- embed: ["contact"]
1294
+ offset: options.offset
1179
1295
  });
1180
1296
  if (options.json) {
1181
1297
  printJson(invoices);
@@ -1312,20 +1428,23 @@ var list_default$4 = defineCommand({
1312
1428
  startDate: z.string().optional().describe("Only orders on or after this date as dd.mm.yyyy or Unix timestamp."),
1313
1429
  endDate: z.string().optional().describe("Only orders on or before this date as dd.mm.yyyy or Unix timestamp."),
1314
1430
  contact: z.coerce.number().optional().describe("ID of the contact whose orders to list."),
1315
- limit: z.coerce.number().optional().describe("Maximum number of orders to return."),
1431
+ limit: z.coerce.number().optional().describe("Maximum number of orders to return. Defaults to all of them."),
1316
1432
  offset: z.coerce.number().optional().describe("Number of orders to skip."),
1317
1433
  json: z.boolean().default(false).describe("Output in JSON format.")
1318
1434
  })),
1319
1435
  action: async (options) => {
1320
- const orders = await (await requireClient()).orders.list({
1436
+ const client = await requireClient();
1437
+ const orders = await fetchAll((page) => client.orders.list({
1321
1438
  status: options.status,
1322
1439
  orderNumber: options.orderNumber,
1323
1440
  startDate: options.startDate,
1324
1441
  endDate: options.endDate,
1325
1442
  contactId: options.contact,
1443
+ embed: ["contact"],
1444
+ ...page
1445
+ }), {
1326
1446
  limit: options.limit,
1327
- offset: options.offset,
1328
- embed: ["contact"]
1447
+ offset: options.offset
1329
1448
  });
1330
1449
  if (options.json) {
1331
1450
  printJson(orders);
@@ -1417,14 +1536,17 @@ var list_default$3 = defineCommand({
1417
1536
  options: defineOptions(z.object({
1418
1537
  name: z.string().optional().describe("Filter by part name."),
1419
1538
  partNumber: z.string().optional().describe("Filter by part number."),
1420
- limit: z.coerce.number().optional().describe("Maximum number of parts to return."),
1539
+ limit: z.coerce.number().optional().describe("Maximum number of parts to return. Defaults to all of them."),
1421
1540
  offset: z.coerce.number().optional().describe("Number of parts to skip."),
1422
1541
  json: z.boolean().default(false).describe("Output in JSON format.")
1423
1542
  })),
1424
1543
  action: async (options) => {
1425
- const parts = await (await requireClient()).parts.list({
1544
+ const client = await requireClient();
1545
+ const parts = await fetchAll((page) => client.parts.list({
1426
1546
  name: options.name,
1427
1547
  partNumber: options.partNumber,
1548
+ ...page
1549
+ }), {
1428
1550
  limit: options.limit,
1429
1551
  offset: options.offset
1430
1552
  });
@@ -1533,12 +1655,13 @@ var delete_default = defineCommand({
1533
1655
  var list_default$2 = defineCommand({
1534
1656
  description: "List tags.",
1535
1657
  options: defineOptions(z.object({
1536
- limit: z.coerce.number().optional().describe("Maximum number of tags to return."),
1658
+ limit: z.coerce.number().optional().describe("Maximum number of tags to return. Defaults to all of them."),
1537
1659
  offset: z.coerce.number().optional().describe("Number of tags to skip."),
1538
1660
  json: z.boolean().default(false).describe("Output in JSON format.")
1539
1661
  })),
1540
1662
  action: async (options) => {
1541
- const tags = await (await requireClient()).tags.list({
1663
+ const client = await requireClient();
1664
+ const tags = await fetchAll((page) => client.tags.list(page), {
1542
1665
  limit: options.limit,
1543
1666
  offset: options.offset
1544
1667
  });
@@ -1644,26 +1767,29 @@ var list_default$1 = defineCommand({
1644
1767
  description: "List transactions of your check accounts.",
1645
1768
  options: defineOptions(z.object({
1646
1769
  checkAccount: z.coerce.number().optional().describe("Only show transactions of this check account ID."),
1647
- unbooked: z.boolean().default(false).describe("Only show transactions with status 100 (created). Filtered client-side because the sevdesk API ignores its isBooked=false filter, so a page fetched with --limit may yield fewer rows."),
1770
+ unbooked: z.boolean().default(false).describe("Only show transactions with status 100 (created). Filtered client-side because the sevdesk API ignores its isBooked=false filter."),
1648
1771
  startDate: z.string().optional().describe("Only show transactions on or after this date (ISO 8601)."),
1649
1772
  endDate: z.string().optional().describe("Only show transactions on or before this date (ISO 8601)."),
1650
1773
  payee: z.string().optional().describe("Only show transactions with this payee or payer name."),
1651
1774
  purpose: z.string().optional().describe("Only show transactions with this payment purpose."),
1652
- limit: z.coerce.number().optional().describe("The maximum number of transactions to return."),
1775
+ limit: z.coerce.number().optional().describe("The maximum number of transactions to return. Defaults to all of them."),
1653
1776
  offset: z.coerce.number().optional().describe("The number of transactions to skip."),
1654
1777
  json: z.boolean().default(false).describe("Output in JSON format.")
1655
1778
  })),
1656
1779
  action: async (options) => {
1657
- let transactions = await (await requireClient()).transactions.list({
1780
+ const client = await requireClient();
1781
+ const transactions = await fetchAll((page) => client.transactions.list({
1658
1782
  checkAccountId: options.checkAccount,
1659
1783
  startDate: options.startDate,
1660
1784
  endDate: options.endDate,
1661
1785
  payeePayerName: options.payee,
1662
1786
  paymtPurpose: options.purpose,
1787
+ ...page
1788
+ }), {
1663
1789
  limit: options.limit,
1664
- offset: options.offset
1790
+ offset: options.offset,
1791
+ keep: options.unbooked ? (transaction) => transaction.status === "100" : void 0
1665
1792
  });
1666
- if (options.unbooked) transactions = transactions.filter((transaction) => transaction.status === "100");
1667
1793
  if (options.json) {
1668
1794
  printJson(transactions);
1669
1795
  return;
@@ -1756,6 +1882,8 @@ var create_default = defineCommand({
1756
1882
  taxRate: z.coerce.number().default(19).describe("Tax rate of the voucher position in percent."),
1757
1883
  voucherDate: z.string().optional().describe("Date as dd.mm.yyyy or Unix timestamp."),
1758
1884
  payDate: z.string().optional().describe("Date as dd.mm.yyyy or Unix timestamp."),
1885
+ deliveryDate: z.string().optional().describe("Start of the service period, or the single service date, as dd.mm.yyyy or Unix timestamp."),
1886
+ deliveryDateUntil: z.string().optional().describe("End of the service period as dd.mm.yyyy or Unix timestamp. Requires --delivery-date."),
1759
1887
  supplierId: z.coerce.number().optional().describe("ID of the supplier contact."),
1760
1888
  supplierName: z.string().optional().describe("Name of the supplier, used when no supplier ID is given."),
1761
1889
  description: z.string().optional().describe("The voucher number."),
@@ -1763,6 +1891,10 @@ var create_default = defineCommand({
1763
1891
  json: z.boolean().default(false).describe("Output in JSON format.")
1764
1892
  })),
1765
1893
  action: async (options) => {
1894
+ if (options.deliveryDateUntil !== void 0 && options.deliveryDate === void 0) {
1895
+ consola.error("You must provide --delivery-date when using --delivery-date-until.");
1896
+ process.exit(1);
1897
+ }
1766
1898
  const client = await requireClient();
1767
1899
  const path = await requireStringOption({
1768
1900
  value: options.file,
@@ -1802,6 +1934,8 @@ var create_default = defineCommand({
1802
1934
  taxRuleId,
1803
1935
  voucherDate: options.voucherDate,
1804
1936
  payDate: options.payDate,
1937
+ deliveryDate: options.deliveryDate,
1938
+ deliveryDateUntil: options.deliveryDateUntil,
1805
1939
  supplierId: options.supplierId,
1806
1940
  supplierName,
1807
1941
  description: options.description
@@ -1876,6 +2010,7 @@ var get_default = defineCommand({
1876
2010
  consola.info(`ID: ${voucher.id}`);
1877
2011
  consola.info(`Status: ${voucher.status ?? "-"}`);
1878
2012
  consola.info(`Date: ${voucher.voucherDate ?? "-"}`);
2013
+ consola.info(`Service period: ${servicePeriodLabel(voucher.deliveryDate, voucher.deliveryDateUntil) || "-"}`);
1879
2014
  consola.info(`Supplier: ${voucher.supplierName ?? contactLabel(voucher.supplier)}`);
1880
2015
  consola.info(`Description: ${voucher.description ?? "-"}`);
1881
2016
  consola.info(`Net: ${voucher.sumNet}`);
@@ -1896,21 +2031,24 @@ var list_default = defineCommand({
1896
2031
  startDate: z.string().optional().describe("Only vouchers on or after this date as dd.mm.yyyy or Unix timestamp."),
1897
2032
  endDate: z.string().optional().describe("Only vouchers on or before this date as dd.mm.yyyy or Unix timestamp."),
1898
2033
  contact: z.coerce.number().optional().describe("ID of the contact whose vouchers to list."),
1899
- limit: z.coerce.number().optional().describe("Maximum number of vouchers to return."),
2034
+ limit: z.coerce.number().optional().describe("Maximum number of vouchers to return. Defaults to all of them."),
1900
2035
  offset: z.coerce.number().optional().describe("Number of vouchers to skip."),
1901
2036
  json: z.boolean().default(false).describe("Output in JSON format.")
1902
2037
  })),
1903
2038
  action: async (options) => {
1904
- const vouchers = await (await requireClient()).vouchers.list({
2039
+ const client = await requireClient();
2040
+ const vouchers = await fetchAll((page) => client.vouchers.list({
1905
2041
  status: options.status,
1906
2042
  creditDebit: options.creditDebit,
1907
2043
  descriptionLike: options.descriptionLike,
1908
2044
  startDate: options.startDate,
1909
2045
  endDate: options.endDate,
1910
2046
  contactId: options.contact,
2047
+ embed: ["supplier"],
2048
+ ...page
2049
+ }), {
1911
2050
  limit: options.limit,
1912
- offset: options.offset,
1913
- embed: ["supplier"]
2051
+ offset: options.offset
1914
2052
  });
1915
2053
  if (options.json) {
1916
2054
  printJson(vouchers);
@@ -1923,6 +2061,7 @@ var list_default = defineCommand({
1923
2061
  printTable(vouchers.map((voucher) => ({
1924
2062
  id: voucher.id,
1925
2063
  date: voucher.voucherDate ?? "",
2064
+ servicePeriod: servicePeriodLabel(voucher.deliveryDate, voucher.deliveryDateUntil),
1926
2065
  supplier: voucher.supplierName ?? contactLabel(voucher.supplier),
1927
2066
  description: voucher.description ?? "",
1928
2067
  gross: voucher.sumGross,
@@ -1936,16 +2075,19 @@ var positions_default = defineCommand({
1936
2075
  description: "List voucher positions.",
1937
2076
  options: defineOptions(z.object({
1938
2077
  voucher: z.coerce.number().optional().describe("ID of the voucher whose positions to list."),
1939
- limit: z.coerce.number().optional().describe("Maximum number of positions to return."),
2078
+ limit: z.coerce.number().optional().describe("Maximum number of positions to return. Defaults to all of them."),
1940
2079
  offset: z.coerce.number().optional().describe("Number of positions to skip."),
1941
2080
  json: z.boolean().default(false).describe("Output in JSON format.")
1942
2081
  })),
1943
2082
  action: async (options) => {
1944
- const positions = await (await requireClient()).vouchers.listPositions({
2083
+ const client = await requireClient();
2084
+ const positions = await fetchAll((page) => client.vouchers.listPositions({
1945
2085
  voucherId: options.voucher,
2086
+ embed: ["accountDatev"],
2087
+ ...page
2088
+ }), {
1946
2089
  limit: options.limit,
1947
- offset: options.offset,
1948
- embed: ["accountDatev"]
2090
+ offset: options.offset
1949
2091
  });
1950
2092
  if (options.json) {
1951
2093
  printJson(positions);
@@ -2053,9 +2195,11 @@ const config = defineConfig({
2053
2195
  "contacts:add-phone": add_phone_default,
2054
2196
  "contacts:create": create_default$3,
2055
2197
  "contacts:delete": delete_default$1,
2198
+ "contacts:delete-address": delete_address_default,
2056
2199
  "contacts:get": get_default$6,
2057
2200
  "contacts:list": list_default$7,
2058
2201
  "contacts:update": update_default,
2202
+ "contacts:update-address": update_address_default,
2059
2203
  "credit-notes:get": get_default$5,
2060
2204
  "credit-notes:list": list_default$6,
2061
2205
  "credit-notes:pdf": pdf_default$2,