@genz-its/sevdesk-cli 0.1.3 → 0.1.4

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
@@ -187,8 +187,8 @@ sevdesk accounts-datev:list [options]
187
187
 
188
188
  - `--number`: Only show accounts with this account number. Filtered client-side across all visible accounts.
189
189
  - `--name-like`: Only show accounts whose name contains this text. Filtered client-side across all visible accounts.
190
- - `--limit`: Maximum number of accounts to return.
191
- - `--offset`: Number of accounts to skip. Ignored when a filter is used.
190
+ - `--limit`: Maximum number of accounts to return. Defaults to all of them.
191
+ - `--offset`: Number of accounts to skip before filtering.
192
192
  - `--json`: Output in JSON format.
193
193
 
194
194
  ### `accounts:balance`
@@ -258,7 +258,7 @@ sevdesk accounts:list [options]
258
258
 
259
259
  **Options:**
260
260
 
261
- - `--limit`: The maximum number of check accounts to return.
261
+ - `--limit`: The maximum number of check accounts to return. Defaults to all of them.
262
262
  - `--offset`: The number of check accounts to skip.
263
263
  - `--json`: Output in JSON format.
264
264
 
@@ -373,7 +373,7 @@ sevdesk contacts:list [options]
373
373
  - `--customer-number`: Filter by customer number.
374
374
  - `--depth`: Contact depth: `0` returns only organizations, `1` organizations and persons. Defaults to `0`.
375
375
  - `--category`: ID of the contact category to filter by: `2` supplier, `3` customer, `4` partner.
376
- - `--limit`: Maximum number of contacts to return.
376
+ - `--limit`: Maximum number of contacts to return. Defaults to all of them.
377
377
  - `--offset`: Number of contacts to skip.
378
378
  - `--json`: Output in JSON format.
379
379
 
@@ -426,7 +426,7 @@ sevdesk credit-notes:list [options]
426
426
  - `--start-date`: Only credit notes on or after this date as `dd.mm.yyyy` or Unix timestamp.
427
427
  - `--end-date`: Only credit notes on or before this date as `dd.mm.yyyy` or Unix timestamp.
428
428
  - `--contact`: ID of the contact whose credit notes to list.
429
- - `--limit`: Maximum number of credit notes to return.
429
+ - `--limit`: Maximum number of credit notes to return. Defaults to all of them.
430
430
  - `--offset`: Number of credit notes to skip.
431
431
  - `--json`: Output in JSON format.
432
432
 
@@ -569,7 +569,7 @@ sevdesk invoices:list [options]
569
569
  - `--start-date`: Only invoices on or after this date as `dd.mm.yyyy` or Unix timestamp.
570
570
  - `--end-date`: Only invoices on or before this date as `dd.mm.yyyy` or Unix timestamp.
571
571
  - `--contact`: ID of the contact whose invoices to list.
572
- - `--limit`: Maximum number of invoices to return.
572
+ - `--limit`: Maximum number of invoices to return. Defaults to all of them.
573
573
  - `--offset`: Number of invoices to skip.
574
574
  - `--json`: Output in JSON format.
575
575
 
@@ -616,7 +616,7 @@ sevdesk orders:list [options]
616
616
  - `--start-date`: Only orders on or after this date as `dd.mm.yyyy` or Unix timestamp.
617
617
  - `--end-date`: Only orders on or before this date as `dd.mm.yyyy` or Unix timestamp.
618
618
  - `--contact`: ID of the contact whose orders to list.
619
- - `--limit`: Maximum number of orders to return.
619
+ - `--limit`: Maximum number of orders to return. Defaults to all of them.
620
620
  - `--offset`: Number of orders to skip.
621
621
  - `--json`: Output in JSON format.
622
622
 
@@ -660,7 +660,7 @@ sevdesk parts:list [options]
660
660
 
661
661
  - `--name`: Filter by part name.
662
662
  - `--part-number`: Filter by part number.
663
- - `--limit`: Maximum number of parts to return.
663
+ - `--limit`: Maximum number of parts to return. Defaults to all of them.
664
664
  - `--offset`: Number of parts to skip.
665
665
  - `--json`: Output in JSON format.
666
666
 
@@ -703,7 +703,7 @@ sevdesk tags:list [options]
703
703
 
704
704
  **Options:**
705
705
 
706
- - `--limit`: Maximum number of tags to return.
706
+ - `--limit`: Maximum number of tags to return. Defaults to all of them.
707
707
  - `--offset`: Number of tags to skip.
708
708
  - `--json`: Output in JSON format.
709
709
 
@@ -750,12 +750,12 @@ sevdesk transactions:list [options]
750
750
  **Options:**
751
751
 
752
752
  - `--check-account`: Only show transactions of this check account ID.
753
- - `--unbooked`: 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. Defaults to `false`.
753
+ - `--unbooked`: Only show transactions with status `100` (created). Filtered client-side because the sevdesk API ignores its `isBooked=false` filter. Defaults to `false`.
754
754
  - `--start-date`: Only show transactions on or after this date (ISO 8601).
755
755
  - `--end-date`: Only show transactions on or before this date (ISO 8601).
756
756
  - `--payee`: Only show transactions with this payee or payer name.
757
757
  - `--purpose`: Only show transactions with this payment purpose.
758
- - `--limit`: The maximum number of transactions to return.
758
+ - `--limit`: The maximum number of transactions to return. Defaults to all of them.
759
759
  - `--offset`: The number of transactions to skip.
760
760
  - `--json`: Output in JSON format.
761
761
 
@@ -799,6 +799,8 @@ sevdesk vouchers:create [options]
799
799
  - `--tax-rate`: Tax rate of the voucher position in percent. Defaults to `19`.
800
800
  - `--voucher-date`: Date as `dd.mm.yyyy` or Unix timestamp.
801
801
  - `--pay-date`: Date as `dd.mm.yyyy` or Unix timestamp.
802
+ - `--delivery-date`: Start of the service period (Leistungszeitraum), or the single service date, as `dd.mm.yyyy` or Unix timestamp.
803
+ - `--delivery-date-until`: End of the service period as `dd.mm.yyyy` or Unix timestamp. Requires `--delivery-date`.
802
804
  - `--supplier-id`: ID of the supplier contact.
803
805
  - `--supplier-name`: Name of the supplier, used when no supplier ID is given.
804
806
  - `--description`: The voucher number.
@@ -848,7 +850,7 @@ sevdesk vouchers:list [options]
848
850
  - `--start-date`: Only vouchers on or after this date as `dd.mm.yyyy` or Unix timestamp.
849
851
  - `--end-date`: Only vouchers on or before this date as `dd.mm.yyyy` or Unix timestamp.
850
852
  - `--contact`: ID of the contact whose vouchers to list.
851
- - `--limit`: Maximum number of vouchers to return.
853
+ - `--limit`: Maximum number of vouchers to return. Defaults to all of them.
852
854
  - `--offset`: Number of vouchers to skip.
853
855
  - `--json`: Output in JSON format.
854
856
 
@@ -863,7 +865,7 @@ sevdesk vouchers:positions [options]
863
865
  **Options:**
864
866
 
865
867
  - `--voucher`: ID of the voucher whose positions to list.
866
- - `--limit`: Maximum number of positions to return.
868
+ - `--limit`: Maximum number of positions to return. Defaults to all of them.
867
869
  - `--offset`: Number of positions to skip.
868
870
  - `--json`: Output in JSON format.
869
871
 
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
  });
@@ -589,8 +621,6 @@ var delete_default$1 = defineCommand({
589
621
  });
590
622
  //#endregion
591
623
  //#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
624
  var get_default$6 = defineCommand({
595
625
  description: "Show a single contact with its addresses and communication ways.",
596
626
  options: defineOptions(z.object({
@@ -605,8 +635,12 @@ var get_default$6 = defineCommand({
605
635
  question: "Enter the contact ID:"
606
636
  });
607
637
  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 });
638
+ /** The `/ContactAddress` endpoint cannot filter by contact, so we filter here. */
639
+ const addresses = await fetchAll((page) => client.contactAddresses.list(page), { keep: (address) => address.contact.id === String(contactId) });
640
+ const communicationWays = await fetchAll((page) => client.communicationWays.list({
641
+ contactId,
642
+ ...page
643
+ }));
610
644
  if (options.json) {
611
645
  printJson({
612
646
  contact,
@@ -653,16 +687,19 @@ var list_default$7 = defineCommand({
653
687
  customerNumber: z.string().optional().describe("Filter by customer number."),
654
688
  depth: z.coerce.number().optional().describe("Contact depth: 0 returns only organizations, 1 organizations and persons. Defaults to 0."),
655
689
  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."),
690
+ limit: z.coerce.number().optional().describe("Maximum number of contacts to return. Defaults to all of them."),
657
691
  offset: z.coerce.number().optional().describe("Number of contacts to skip."),
658
692
  json: z.boolean().default(false).describe("Output in JSON format.")
659
693
  })),
660
694
  action: async (options) => {
661
- const contacts = await (await requireClient()).contacts.list({
695
+ const client = await requireClient();
696
+ const contacts = await fetchAll((page) => client.contacts.list({
662
697
  name: options.name,
663
698
  customerNumber: options.customerNumber,
664
699
  depth: toDepth(options.depth),
665
700
  categoryId: options.category,
701
+ ...page
702
+ }), {
666
703
  limit: options.limit,
667
704
  offset: options.offset
668
705
  });
@@ -775,20 +812,23 @@ var list_default$6 = defineCommand({
775
812
  startDate: z.string().optional().describe("Only credit notes on or after this date as dd.mm.yyyy or Unix timestamp."),
776
813
  endDate: z.string().optional().describe("Only credit notes on or before this date as dd.mm.yyyy or Unix timestamp."),
777
814
  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."),
815
+ limit: z.coerce.number().optional().describe("Maximum number of credit notes to return. Defaults to all of them."),
779
816
  offset: z.coerce.number().optional().describe("Number of credit notes to skip."),
780
817
  json: z.boolean().default(false).describe("Output in JSON format.")
781
818
  })),
782
819
  action: async (options) => {
783
- const creditNotes = await (await requireClient()).creditNotes.list({
820
+ const client = await requireClient();
821
+ const creditNotes = await fetchAll((page) => client.creditNotes.list({
784
822
  status: options.status,
785
823
  creditNoteNumber: options.creditNoteNumber,
786
824
  startDate: options.startDate,
787
825
  endDate: options.endDate,
788
826
  contactId: options.contact,
827
+ embed: ["contact"],
828
+ ...page
829
+ }), {
789
830
  limit: options.limit,
790
- offset: options.offset,
791
- embed: ["contact"]
831
+ offset: options.offset
792
832
  });
793
833
  if (options.json) {
794
834
  printJson(creditNotes);
@@ -1162,20 +1202,23 @@ var list_default$5 = defineCommand({
1162
1202
  startDate: z.string().optional().describe("Only invoices on or after this date as dd.mm.yyyy or Unix timestamp."),
1163
1203
  endDate: z.string().optional().describe("Only invoices on or before this date as dd.mm.yyyy or Unix timestamp."),
1164
1204
  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."),
1205
+ limit: z.coerce.number().optional().describe("Maximum number of invoices to return. Defaults to all of them."),
1166
1206
  offset: z.coerce.number().optional().describe("Number of invoices to skip."),
1167
1207
  json: z.boolean().default(false).describe("Output in JSON format.")
1168
1208
  })),
1169
1209
  action: async (options) => {
1170
- const invoices = await (await requireClient()).invoices.list({
1210
+ const client = await requireClient();
1211
+ const invoices = await fetchAll((page) => client.invoices.list({
1171
1212
  status: options.status,
1172
1213
  invoiceNumber: options.invoiceNumber,
1173
1214
  startDate: options.startDate,
1174
1215
  endDate: options.endDate,
1175
1216
  contactId: options.contact,
1217
+ embed: ["contact"],
1218
+ ...page
1219
+ }), {
1176
1220
  limit: options.limit,
1177
- offset: options.offset,
1178
- embed: ["contact"]
1221
+ offset: options.offset
1179
1222
  });
1180
1223
  if (options.json) {
1181
1224
  printJson(invoices);
@@ -1312,20 +1355,23 @@ var list_default$4 = defineCommand({
1312
1355
  startDate: z.string().optional().describe("Only orders on or after this date as dd.mm.yyyy or Unix timestamp."),
1313
1356
  endDate: z.string().optional().describe("Only orders on or before this date as dd.mm.yyyy or Unix timestamp."),
1314
1357
  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."),
1358
+ limit: z.coerce.number().optional().describe("Maximum number of orders to return. Defaults to all of them."),
1316
1359
  offset: z.coerce.number().optional().describe("Number of orders to skip."),
1317
1360
  json: z.boolean().default(false).describe("Output in JSON format.")
1318
1361
  })),
1319
1362
  action: async (options) => {
1320
- const orders = await (await requireClient()).orders.list({
1363
+ const client = await requireClient();
1364
+ const orders = await fetchAll((page) => client.orders.list({
1321
1365
  status: options.status,
1322
1366
  orderNumber: options.orderNumber,
1323
1367
  startDate: options.startDate,
1324
1368
  endDate: options.endDate,
1325
1369
  contactId: options.contact,
1370
+ embed: ["contact"],
1371
+ ...page
1372
+ }), {
1326
1373
  limit: options.limit,
1327
- offset: options.offset,
1328
- embed: ["contact"]
1374
+ offset: options.offset
1329
1375
  });
1330
1376
  if (options.json) {
1331
1377
  printJson(orders);
@@ -1417,14 +1463,17 @@ var list_default$3 = defineCommand({
1417
1463
  options: defineOptions(z.object({
1418
1464
  name: z.string().optional().describe("Filter by part name."),
1419
1465
  partNumber: z.string().optional().describe("Filter by part number."),
1420
- limit: z.coerce.number().optional().describe("Maximum number of parts to return."),
1466
+ limit: z.coerce.number().optional().describe("Maximum number of parts to return. Defaults to all of them."),
1421
1467
  offset: z.coerce.number().optional().describe("Number of parts to skip."),
1422
1468
  json: z.boolean().default(false).describe("Output in JSON format.")
1423
1469
  })),
1424
1470
  action: async (options) => {
1425
- const parts = await (await requireClient()).parts.list({
1471
+ const client = await requireClient();
1472
+ const parts = await fetchAll((page) => client.parts.list({
1426
1473
  name: options.name,
1427
1474
  partNumber: options.partNumber,
1475
+ ...page
1476
+ }), {
1428
1477
  limit: options.limit,
1429
1478
  offset: options.offset
1430
1479
  });
@@ -1533,12 +1582,13 @@ var delete_default = defineCommand({
1533
1582
  var list_default$2 = defineCommand({
1534
1583
  description: "List tags.",
1535
1584
  options: defineOptions(z.object({
1536
- limit: z.coerce.number().optional().describe("Maximum number of tags to return."),
1585
+ limit: z.coerce.number().optional().describe("Maximum number of tags to return. Defaults to all of them."),
1537
1586
  offset: z.coerce.number().optional().describe("Number of tags to skip."),
1538
1587
  json: z.boolean().default(false).describe("Output in JSON format.")
1539
1588
  })),
1540
1589
  action: async (options) => {
1541
- const tags = await (await requireClient()).tags.list({
1590
+ const client = await requireClient();
1591
+ const tags = await fetchAll((page) => client.tags.list(page), {
1542
1592
  limit: options.limit,
1543
1593
  offset: options.offset
1544
1594
  });
@@ -1644,26 +1694,29 @@ var list_default$1 = defineCommand({
1644
1694
  description: "List transactions of your check accounts.",
1645
1695
  options: defineOptions(z.object({
1646
1696
  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."),
1697
+ 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
1698
  startDate: z.string().optional().describe("Only show transactions on or after this date (ISO 8601)."),
1649
1699
  endDate: z.string().optional().describe("Only show transactions on or before this date (ISO 8601)."),
1650
1700
  payee: z.string().optional().describe("Only show transactions with this payee or payer name."),
1651
1701
  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."),
1702
+ limit: z.coerce.number().optional().describe("The maximum number of transactions to return. Defaults to all of them."),
1653
1703
  offset: z.coerce.number().optional().describe("The number of transactions to skip."),
1654
1704
  json: z.boolean().default(false).describe("Output in JSON format.")
1655
1705
  })),
1656
1706
  action: async (options) => {
1657
- let transactions = await (await requireClient()).transactions.list({
1707
+ const client = await requireClient();
1708
+ const transactions = await fetchAll((page) => client.transactions.list({
1658
1709
  checkAccountId: options.checkAccount,
1659
1710
  startDate: options.startDate,
1660
1711
  endDate: options.endDate,
1661
1712
  payeePayerName: options.payee,
1662
1713
  paymtPurpose: options.purpose,
1714
+ ...page
1715
+ }), {
1663
1716
  limit: options.limit,
1664
- offset: options.offset
1717
+ offset: options.offset,
1718
+ keep: options.unbooked ? (transaction) => transaction.status === "100" : void 0
1665
1719
  });
1666
- if (options.unbooked) transactions = transactions.filter((transaction) => transaction.status === "100");
1667
1720
  if (options.json) {
1668
1721
  printJson(transactions);
1669
1722
  return;
@@ -1756,6 +1809,8 @@ var create_default = defineCommand({
1756
1809
  taxRate: z.coerce.number().default(19).describe("Tax rate of the voucher position in percent."),
1757
1810
  voucherDate: z.string().optional().describe("Date as dd.mm.yyyy or Unix timestamp."),
1758
1811
  payDate: z.string().optional().describe("Date as dd.mm.yyyy or Unix timestamp."),
1812
+ deliveryDate: z.string().optional().describe("Start of the service period, or the single service date, as dd.mm.yyyy or Unix timestamp."),
1813
+ deliveryDateUntil: z.string().optional().describe("End of the service period as dd.mm.yyyy or Unix timestamp. Requires --delivery-date."),
1759
1814
  supplierId: z.coerce.number().optional().describe("ID of the supplier contact."),
1760
1815
  supplierName: z.string().optional().describe("Name of the supplier, used when no supplier ID is given."),
1761
1816
  description: z.string().optional().describe("The voucher number."),
@@ -1763,6 +1818,10 @@ var create_default = defineCommand({
1763
1818
  json: z.boolean().default(false).describe("Output in JSON format.")
1764
1819
  })),
1765
1820
  action: async (options) => {
1821
+ if (options.deliveryDateUntil !== void 0 && options.deliveryDate === void 0) {
1822
+ consola.error("You must provide --delivery-date when using --delivery-date-until.");
1823
+ process.exit(1);
1824
+ }
1766
1825
  const client = await requireClient();
1767
1826
  const path = await requireStringOption({
1768
1827
  value: options.file,
@@ -1802,6 +1861,8 @@ var create_default = defineCommand({
1802
1861
  taxRuleId,
1803
1862
  voucherDate: options.voucherDate,
1804
1863
  payDate: options.payDate,
1864
+ deliveryDate: options.deliveryDate,
1865
+ deliveryDateUntil: options.deliveryDateUntil,
1805
1866
  supplierId: options.supplierId,
1806
1867
  supplierName,
1807
1868
  description: options.description
@@ -1876,6 +1937,7 @@ var get_default = defineCommand({
1876
1937
  consola.info(`ID: ${voucher.id}`);
1877
1938
  consola.info(`Status: ${voucher.status ?? "-"}`);
1878
1939
  consola.info(`Date: ${voucher.voucherDate ?? "-"}`);
1940
+ consola.info(`Service period: ${servicePeriodLabel(voucher.deliveryDate, voucher.deliveryDateUntil) || "-"}`);
1879
1941
  consola.info(`Supplier: ${voucher.supplierName ?? contactLabel(voucher.supplier)}`);
1880
1942
  consola.info(`Description: ${voucher.description ?? "-"}`);
1881
1943
  consola.info(`Net: ${voucher.sumNet}`);
@@ -1896,21 +1958,24 @@ var list_default = defineCommand({
1896
1958
  startDate: z.string().optional().describe("Only vouchers on or after this date as dd.mm.yyyy or Unix timestamp."),
1897
1959
  endDate: z.string().optional().describe("Only vouchers on or before this date as dd.mm.yyyy or Unix timestamp."),
1898
1960
  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."),
1961
+ limit: z.coerce.number().optional().describe("Maximum number of vouchers to return. Defaults to all of them."),
1900
1962
  offset: z.coerce.number().optional().describe("Number of vouchers to skip."),
1901
1963
  json: z.boolean().default(false).describe("Output in JSON format.")
1902
1964
  })),
1903
1965
  action: async (options) => {
1904
- const vouchers = await (await requireClient()).vouchers.list({
1966
+ const client = await requireClient();
1967
+ const vouchers = await fetchAll((page) => client.vouchers.list({
1905
1968
  status: options.status,
1906
1969
  creditDebit: options.creditDebit,
1907
1970
  descriptionLike: options.descriptionLike,
1908
1971
  startDate: options.startDate,
1909
1972
  endDate: options.endDate,
1910
1973
  contactId: options.contact,
1974
+ embed: ["supplier"],
1975
+ ...page
1976
+ }), {
1911
1977
  limit: options.limit,
1912
- offset: options.offset,
1913
- embed: ["supplier"]
1978
+ offset: options.offset
1914
1979
  });
1915
1980
  if (options.json) {
1916
1981
  printJson(vouchers);
@@ -1923,6 +1988,7 @@ var list_default = defineCommand({
1923
1988
  printTable(vouchers.map((voucher) => ({
1924
1989
  id: voucher.id,
1925
1990
  date: voucher.voucherDate ?? "",
1991
+ servicePeriod: servicePeriodLabel(voucher.deliveryDate, voucher.deliveryDateUntil),
1926
1992
  supplier: voucher.supplierName ?? contactLabel(voucher.supplier),
1927
1993
  description: voucher.description ?? "",
1928
1994
  gross: voucher.sumGross,
@@ -1936,16 +2002,19 @@ var positions_default = defineCommand({
1936
2002
  description: "List voucher positions.",
1937
2003
  options: defineOptions(z.object({
1938
2004
  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."),
2005
+ limit: z.coerce.number().optional().describe("Maximum number of positions to return. Defaults to all of them."),
1940
2006
  offset: z.coerce.number().optional().describe("Number of positions to skip."),
1941
2007
  json: z.boolean().default(false).describe("Output in JSON format.")
1942
2008
  })),
1943
2009
  action: async (options) => {
1944
- const positions = await (await requireClient()).vouchers.listPositions({
2010
+ const client = await requireClient();
2011
+ const positions = await fetchAll((page) => client.vouchers.listPositions({
1945
2012
  voucherId: options.voucher,
2013
+ embed: ["accountDatev"],
2014
+ ...page
2015
+ }), {
1946
2016
  limit: options.limit,
1947
- offset: options.offset,
1948
- embed: ["accountDatev"]
2017
+ offset: options.offset
1949
2018
  });
1950
2019
  if (options.json) {
1951
2020
  printJson(positions);