@genz-its/sevdesk-cli 0.1.2 → 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
@@ -83,6 +83,8 @@ sevdesk transactions:list --unbooked --json | jq -r '.[].id'
83
83
  - [`login`](#login)
84
84
  - [`logout`](#logout)
85
85
  - [`doctor`](#doctor)
86
+ - [`accounts-datev:get`](#accounts-datevget)
87
+ - [`accounts-datev:list`](#accounts-datevlist)
86
88
  - [`accounts:balance`](#accountsbalance)
87
89
  - [`accounts:create-clearing`](#accountscreate-clearing)
88
90
  - [`accounts:create-file-import`](#accountscreate-file-import)
@@ -160,6 +162,35 @@ sevdesk doctor [options]
160
162
 
161
163
  - `--json`: Output in JSON format.
162
164
 
165
+ ### `accounts-datev:get`
166
+
167
+ Show a single booking account (AccountDatev), including hidden accounts that [`accounts-datev:list`](#accounts-datevlist) does not return. Backed by an undocumented sevdesk endpoint that may change without notice.
168
+
169
+ ```bash
170
+ sevdesk accounts-datev:get [options]
171
+ ```
172
+
173
+ **Options:**
174
+
175
+ - `--id`: The booking account ID. If omitted, you will be prompted.
176
+ - `--json`: Output in JSON format.
177
+
178
+ ### `accounts-datev:list`
179
+
180
+ 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`](#accounts-datevget). Backed by an undocumented sevdesk endpoint that may change without notice.
181
+
182
+ ```bash
183
+ sevdesk accounts-datev:list [options]
184
+ ```
185
+
186
+ **Options:**
187
+
188
+ - `--number`: Only show accounts with this account number. Filtered client-side across all visible accounts.
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. Defaults to all of them.
191
+ - `--offset`: Number of accounts to skip before filtering.
192
+ - `--json`: Output in JSON format.
193
+
163
194
  ### `accounts:balance`
164
195
 
165
196
  Show the balance of a check account at a given date. The balance is the sum of all transactions known to sevdesk, which is not necessarily the real bank balance.
@@ -227,7 +258,7 @@ sevdesk accounts:list [options]
227
258
 
228
259
  **Options:**
229
260
 
230
- - `--limit`: The maximum number of check accounts to return.
261
+ - `--limit`: The maximum number of check accounts to return. Defaults to all of them.
231
262
  - `--offset`: The number of check accounts to skip.
232
263
  - `--json`: Output in JSON format.
233
264
 
@@ -342,7 +373,7 @@ sevdesk contacts:list [options]
342
373
  - `--customer-number`: Filter by customer number.
343
374
  - `--depth`: Contact depth: `0` returns only organizations, `1` organizations and persons. Defaults to `0`.
344
375
  - `--category`: ID of the contact category to filter by: `2` supplier, `3` customer, `4` partner.
345
- - `--limit`: Maximum number of contacts to return.
376
+ - `--limit`: Maximum number of contacts to return. Defaults to all of them.
346
377
  - `--offset`: Number of contacts to skip.
347
378
  - `--json`: Output in JSON format.
348
379
 
@@ -395,7 +426,7 @@ sevdesk credit-notes:list [options]
395
426
  - `--start-date`: Only credit notes on or after this date as `dd.mm.yyyy` or Unix timestamp.
396
427
  - `--end-date`: Only credit notes on or before this date as `dd.mm.yyyy` or Unix timestamp.
397
428
  - `--contact`: ID of the contact whose credit notes to list.
398
- - `--limit`: Maximum number of credit notes to return.
429
+ - `--limit`: Maximum number of credit notes to return. Defaults to all of them.
399
430
  - `--offset`: Number of credit notes to skip.
400
431
  - `--json`: Output in JSON format.
401
432
 
@@ -496,7 +527,7 @@ sevdesk export:vouchers [options]
496
527
 
497
528
  ### `guidance:accounts`
498
529
 
499
- List bookable accounts and their allowed tax rules. The first matching filter wins: `--account-number`, `--tax-rule`, `--revenue`, `--expense`. Without a filter, all accounts are listed.
530
+ List bookable accounts and their allowed tax rules. Covers only the ReceiptGuidance subset of VAT-relevant accounts — use [`accounts-datev:list`](#accounts-datevlist) for all booking accounts. The first matching filter wins: `--account-number`, `--tax-rule`, `--revenue`, `--expense`. Without a filter, all accounts are listed.
500
531
 
501
532
  ```bash
502
533
  sevdesk guidance:accounts [options]
@@ -538,7 +569,7 @@ sevdesk invoices:list [options]
538
569
  - `--start-date`: Only invoices on or after this date as `dd.mm.yyyy` or Unix timestamp.
539
570
  - `--end-date`: Only invoices on or before this date as `dd.mm.yyyy` or Unix timestamp.
540
571
  - `--contact`: ID of the contact whose invoices to list.
541
- - `--limit`: Maximum number of invoices to return.
572
+ - `--limit`: Maximum number of invoices to return. Defaults to all of them.
542
573
  - `--offset`: Number of invoices to skip.
543
574
  - `--json`: Output in JSON format.
544
575
 
@@ -585,7 +616,7 @@ sevdesk orders:list [options]
585
616
  - `--start-date`: Only orders on or after this date as `dd.mm.yyyy` or Unix timestamp.
586
617
  - `--end-date`: Only orders on or before this date as `dd.mm.yyyy` or Unix timestamp.
587
618
  - `--contact`: ID of the contact whose orders to list.
588
- - `--limit`: Maximum number of orders to return.
619
+ - `--limit`: Maximum number of orders to return. Defaults to all of them.
589
620
  - `--offset`: Number of orders to skip.
590
621
  - `--json`: Output in JSON format.
591
622
 
@@ -629,7 +660,7 @@ sevdesk parts:list [options]
629
660
 
630
661
  - `--name`: Filter by part name.
631
662
  - `--part-number`: Filter by part number.
632
- - `--limit`: Maximum number of parts to return.
663
+ - `--limit`: Maximum number of parts to return. Defaults to all of them.
633
664
  - `--offset`: Number of parts to skip.
634
665
  - `--json`: Output in JSON format.
635
666
 
@@ -672,7 +703,7 @@ sevdesk tags:list [options]
672
703
 
673
704
  **Options:**
674
705
 
675
- - `--limit`: Maximum number of tags to return.
706
+ - `--limit`: Maximum number of tags to return. Defaults to all of them.
676
707
  - `--offset`: Number of tags to skip.
677
708
  - `--json`: Output in JSON format.
678
709
 
@@ -719,12 +750,12 @@ sevdesk transactions:list [options]
719
750
  **Options:**
720
751
 
721
752
  - `--check-account`: Only show transactions of this check account ID.
722
- - `--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`.
723
754
  - `--start-date`: Only show transactions on or after this date (ISO 8601).
724
755
  - `--end-date`: Only show transactions on or before this date (ISO 8601).
725
756
  - `--payee`: Only show transactions with this payee or payer name.
726
757
  - `--purpose`: Only show transactions with this payment purpose.
727
- - `--limit`: The maximum number of transactions to return.
758
+ - `--limit`: The maximum number of transactions to return. Defaults to all of them.
728
759
  - `--offset`: The number of transactions to skip.
729
760
  - `--json`: Output in JSON format.
730
761
 
@@ -768,6 +799,8 @@ sevdesk vouchers:create [options]
768
799
  - `--tax-rate`: Tax rate of the voucher position in percent. Defaults to `19`.
769
800
  - `--voucher-date`: Date as `dd.mm.yyyy` or Unix timestamp.
770
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`.
771
804
  - `--supplier-id`: ID of the supplier contact.
772
805
  - `--supplier-name`: Name of the supplier, used when no supplier ID is given.
773
806
  - `--description`: The voucher number.
@@ -817,7 +850,7 @@ sevdesk vouchers:list [options]
817
850
  - `--start-date`: Only vouchers on or after this date as `dd.mm.yyyy` or Unix timestamp.
818
851
  - `--end-date`: Only vouchers on or before this date as `dd.mm.yyyy` or Unix timestamp.
819
852
  - `--contact`: ID of the contact whose vouchers to list.
820
- - `--limit`: Maximum number of vouchers to return.
853
+ - `--limit`: Maximum number of vouchers to return. Defaults to all of them.
821
854
  - `--offset`: Number of vouchers to skip.
822
855
  - `--json`: Output in JSON format.
823
856
 
@@ -832,7 +865,7 @@ sevdesk vouchers:positions [options]
832
865
  **Options:**
833
866
 
834
867
  - `--voucher`: ID of the voucher whose positions to list.
835
- - `--limit`: Maximum number of positions to return.
868
+ - `--limit`: Maximum number of positions to return. Defaults to all of them.
836
869
  - `--offset`: Number of positions to skip.
837
870
  - `--json`: Output in JSON format.
838
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
  }
@@ -161,6 +172,109 @@ function printTable(rows) {
161
172
  for (const row of rows) console.log(line(columns.map((column) => row[column] ?? "")));
162
173
  }
163
174
  //#endregion
175
+ //#region src/commands/accounts-datev/get.ts
176
+ var get_default$8 = defineCommand({
177
+ description: "Show a single booking account (AccountDatev), including hidden accounts that accounts-datev:list does not return. Backed by an undocumented sevdesk endpoint that may change without notice.",
178
+ options: defineOptions(z.object({
179
+ id: z.coerce.number().optional().describe("The booking account ID. If omitted, you will be prompted."),
180
+ json: z.boolean().default(false).describe("Output in JSON format.")
181
+ })),
182
+ action: async (options) => {
183
+ const client = await requireClient();
184
+ const accountDatevId = await requireNumberOption({
185
+ value: options.id,
186
+ requirement: "a booking account via --id",
187
+ question: "Enter the booking account ID:"
188
+ });
189
+ const account = await client.accountsDatev.get({ accountDatevId });
190
+ if (options.json) {
191
+ printJson(account);
192
+ return;
193
+ }
194
+ consola.info(`ID: ${account.id}`);
195
+ consola.info(`Number: ${account.number ?? "-"}`);
196
+ consola.info(`Name: ${account.name ?? "-"}`);
197
+ consola.info(`Tax rate: ${account.taxRate ?? "-"}`);
198
+ consola.info(`Deprecated: ${account.deprecated ?? "-"}`);
199
+ consola.info(`Hidden: ${account.hidden ?? "-"}`);
200
+ consola.info(`Deactivated: ${account.deactivated ?? "-"}`);
201
+ }
202
+ });
203
+ //#endregion
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
+ */
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
241
+ var list_default$9 = defineCommand({
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.",
243
+ options: defineOptions(z.object({
244
+ number: z.string().optional().describe("Only show accounts with this account number. Filtered client-side across all visible accounts."),
245
+ nameLike: z.string().optional().describe("Only show accounts whose name contains this text. Filtered client-side across all visible accounts."),
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."),
248
+ json: z.boolean().default(false).describe("Output in JSON format.")
249
+ })),
250
+ action: async (options) => {
251
+ const client = await requireClient();
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), {
255
+ limit: options.limit,
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
258
+ });
259
+ if (options.json) {
260
+ printJson(accounts);
261
+ return;
262
+ }
263
+ if (accounts.length === 0) {
264
+ consola.info("No booking accounts found.");
265
+ return;
266
+ }
267
+ printTable(accounts.map((account) => ({
268
+ id: account.id,
269
+ number: account.number ?? "",
270
+ name: account.name ?? "",
271
+ taxRate: account.taxRate ?? "",
272
+ deprecated: account.deprecated ?? "",
273
+ hidden: account.hidden ?? ""
274
+ })));
275
+ }
276
+ });
277
+ //#endregion
164
278
  //#region src/commands/accounts/balance.ts
165
279
  var balance_default = defineCommand({
166
280
  description: "Show the balance of a check account at a given date.",
@@ -285,12 +399,13 @@ var get_default$7 = defineCommand({
285
399
  var list_default$8 = defineCommand({
286
400
  description: "List your check accounts.",
287
401
  options: defineOptions(z.object({
288
- 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."),
289
403
  offset: z.coerce.number().optional().describe("The number of check accounts to skip."),
290
404
  json: z.boolean().default(false).describe("Output in JSON format.")
291
405
  })),
292
406
  action: async (options) => {
293
- const checkAccounts = await (await requireClient()).checkAccounts.list({
407
+ const client = await requireClient();
408
+ const checkAccounts = await fetchAll((page) => client.checkAccounts.list(page), {
294
409
  limit: options.limit,
295
410
  offset: options.offset
296
411
  });
@@ -506,8 +621,6 @@ var delete_default$1 = defineCommand({
506
621
  });
507
622
  //#endregion
508
623
  //#region src/commands/contacts/get.ts
509
- /** The `/ContactAddress` endpoint cannot filter by contact, so we filter here. */
510
- const ADDRESS_LOOKUP_LIMIT = 100;
511
624
  var get_default$6 = defineCommand({
512
625
  description: "Show a single contact with its addresses and communication ways.",
513
626
  options: defineOptions(z.object({
@@ -522,8 +635,12 @@ var get_default$6 = defineCommand({
522
635
  question: "Enter the contact ID:"
523
636
  });
524
637
  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 });
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
+ }));
527
644
  if (options.json) {
528
645
  printJson({
529
646
  contact,
@@ -570,16 +687,19 @@ var list_default$7 = defineCommand({
570
687
  customerNumber: z.string().optional().describe("Filter by customer number."),
571
688
  depth: z.coerce.number().optional().describe("Contact depth: 0 returns only organizations, 1 organizations and persons. Defaults to 0."),
572
689
  category: z.coerce.number().optional().describe("ID of the contact category to filter by: 2 supplier, 3 customer, 4 partner."),
573
- 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."),
574
691
  offset: z.coerce.number().optional().describe("Number of contacts to skip."),
575
692
  json: z.boolean().default(false).describe("Output in JSON format.")
576
693
  })),
577
694
  action: async (options) => {
578
- const contacts = await (await requireClient()).contacts.list({
695
+ const client = await requireClient();
696
+ const contacts = await fetchAll((page) => client.contacts.list({
579
697
  name: options.name,
580
698
  customerNumber: options.customerNumber,
581
699
  depth: toDepth(options.depth),
582
700
  categoryId: options.category,
701
+ ...page
702
+ }), {
583
703
  limit: options.limit,
584
704
  offset: options.offset
585
705
  });
@@ -692,20 +812,23 @@ var list_default$6 = defineCommand({
692
812
  startDate: z.string().optional().describe("Only credit notes on or after this date as dd.mm.yyyy or Unix timestamp."),
693
813
  endDate: z.string().optional().describe("Only credit notes on or before this date as dd.mm.yyyy or Unix timestamp."),
694
814
  contact: z.coerce.number().optional().describe("ID of the contact whose credit notes to list."),
695
- 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."),
696
816
  offset: z.coerce.number().optional().describe("Number of credit notes to skip."),
697
817
  json: z.boolean().default(false).describe("Output in JSON format.")
698
818
  })),
699
819
  action: async (options) => {
700
- const creditNotes = await (await requireClient()).creditNotes.list({
820
+ const client = await requireClient();
821
+ const creditNotes = await fetchAll((page) => client.creditNotes.list({
701
822
  status: options.status,
702
823
  creditNoteNumber: options.creditNoteNumber,
703
824
  startDate: options.startDate,
704
825
  endDate: options.endDate,
705
826
  contactId: options.contact,
827
+ embed: ["contact"],
828
+ ...page
829
+ }), {
706
830
  limit: options.limit,
707
- offset: options.offset,
708
- embed: ["contact"]
831
+ offset: options.offset
709
832
  });
710
833
  if (options.json) {
711
834
  printJson(creditNotes);
@@ -1003,7 +1126,7 @@ function formatTaxRules(taxRules) {
1003
1126
  return names.join(", ");
1004
1127
  }
1005
1128
  var accounts_default = defineCommand({
1006
- description: "List bookable accounts and their allowed tax rules. The first matching filter wins: --account-number, --tax-rule, --revenue, --expense. Without a filter, all accounts are listed.",
1129
+ description: "List bookable accounts and their allowed tax rules. Covers only the ReceiptGuidance subset of VAT-relevant accounts — use accounts-datev:list for all booking accounts. The first matching filter wins: --account-number, --tax-rule, --revenue, --expense. Without a filter, all accounts are listed.",
1007
1130
  options: defineOptions(z.object({
1008
1131
  accountNumber: z.string().optional().describe("Only show the account with this datev account number."),
1009
1132
  taxRule: z.string().optional().describe("Tax rule name, for example USTPFL_UMS_EINN."),
@@ -1079,20 +1202,23 @@ var list_default$5 = defineCommand({
1079
1202
  startDate: z.string().optional().describe("Only invoices on or after this date as dd.mm.yyyy or Unix timestamp."),
1080
1203
  endDate: z.string().optional().describe("Only invoices on or before this date as dd.mm.yyyy or Unix timestamp."),
1081
1204
  contact: z.coerce.number().optional().describe("ID of the contact whose invoices to list."),
1082
- 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."),
1083
1206
  offset: z.coerce.number().optional().describe("Number of invoices to skip."),
1084
1207
  json: z.boolean().default(false).describe("Output in JSON format.")
1085
1208
  })),
1086
1209
  action: async (options) => {
1087
- const invoices = await (await requireClient()).invoices.list({
1210
+ const client = await requireClient();
1211
+ const invoices = await fetchAll((page) => client.invoices.list({
1088
1212
  status: options.status,
1089
1213
  invoiceNumber: options.invoiceNumber,
1090
1214
  startDate: options.startDate,
1091
1215
  endDate: options.endDate,
1092
1216
  contactId: options.contact,
1217
+ embed: ["contact"],
1218
+ ...page
1219
+ }), {
1093
1220
  limit: options.limit,
1094
- offset: options.offset,
1095
- embed: ["contact"]
1221
+ offset: options.offset
1096
1222
  });
1097
1223
  if (options.json) {
1098
1224
  printJson(invoices);
@@ -1229,20 +1355,23 @@ var list_default$4 = defineCommand({
1229
1355
  startDate: z.string().optional().describe("Only orders on or after this date as dd.mm.yyyy or Unix timestamp."),
1230
1356
  endDate: z.string().optional().describe("Only orders on or before this date as dd.mm.yyyy or Unix timestamp."),
1231
1357
  contact: z.coerce.number().optional().describe("ID of the contact whose orders to list."),
1232
- 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."),
1233
1359
  offset: z.coerce.number().optional().describe("Number of orders to skip."),
1234
1360
  json: z.boolean().default(false).describe("Output in JSON format.")
1235
1361
  })),
1236
1362
  action: async (options) => {
1237
- const orders = await (await requireClient()).orders.list({
1363
+ const client = await requireClient();
1364
+ const orders = await fetchAll((page) => client.orders.list({
1238
1365
  status: options.status,
1239
1366
  orderNumber: options.orderNumber,
1240
1367
  startDate: options.startDate,
1241
1368
  endDate: options.endDate,
1242
1369
  contactId: options.contact,
1370
+ embed: ["contact"],
1371
+ ...page
1372
+ }), {
1243
1373
  limit: options.limit,
1244
- offset: options.offset,
1245
- embed: ["contact"]
1374
+ offset: options.offset
1246
1375
  });
1247
1376
  if (options.json) {
1248
1377
  printJson(orders);
@@ -1334,14 +1463,17 @@ var list_default$3 = defineCommand({
1334
1463
  options: defineOptions(z.object({
1335
1464
  name: z.string().optional().describe("Filter by part name."),
1336
1465
  partNumber: z.string().optional().describe("Filter by part number."),
1337
- 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."),
1338
1467
  offset: z.coerce.number().optional().describe("Number of parts to skip."),
1339
1468
  json: z.boolean().default(false).describe("Output in JSON format.")
1340
1469
  })),
1341
1470
  action: async (options) => {
1342
- const parts = await (await requireClient()).parts.list({
1471
+ const client = await requireClient();
1472
+ const parts = await fetchAll((page) => client.parts.list({
1343
1473
  name: options.name,
1344
1474
  partNumber: options.partNumber,
1475
+ ...page
1476
+ }), {
1345
1477
  limit: options.limit,
1346
1478
  offset: options.offset
1347
1479
  });
@@ -1450,12 +1582,13 @@ var delete_default = defineCommand({
1450
1582
  var list_default$2 = defineCommand({
1451
1583
  description: "List tags.",
1452
1584
  options: defineOptions(z.object({
1453
- 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."),
1454
1586
  offset: z.coerce.number().optional().describe("Number of tags to skip."),
1455
1587
  json: z.boolean().default(false).describe("Output in JSON format.")
1456
1588
  })),
1457
1589
  action: async (options) => {
1458
- const tags = await (await requireClient()).tags.list({
1590
+ const client = await requireClient();
1591
+ const tags = await fetchAll((page) => client.tags.list(page), {
1459
1592
  limit: options.limit,
1460
1593
  offset: options.offset
1461
1594
  });
@@ -1561,26 +1694,29 @@ var list_default$1 = defineCommand({
1561
1694
  description: "List transactions of your check accounts.",
1562
1695
  options: defineOptions(z.object({
1563
1696
  checkAccount: z.coerce.number().optional().describe("Only show transactions of this check account ID."),
1564
- 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."),
1565
1698
  startDate: z.string().optional().describe("Only show transactions on or after this date (ISO 8601)."),
1566
1699
  endDate: z.string().optional().describe("Only show transactions on or before this date (ISO 8601)."),
1567
1700
  payee: z.string().optional().describe("Only show transactions with this payee or payer name."),
1568
1701
  purpose: z.string().optional().describe("Only show transactions with this payment purpose."),
1569
- 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."),
1570
1703
  offset: z.coerce.number().optional().describe("The number of transactions to skip."),
1571
1704
  json: z.boolean().default(false).describe("Output in JSON format.")
1572
1705
  })),
1573
1706
  action: async (options) => {
1574
- let transactions = await (await requireClient()).transactions.list({
1707
+ const client = await requireClient();
1708
+ const transactions = await fetchAll((page) => client.transactions.list({
1575
1709
  checkAccountId: options.checkAccount,
1576
1710
  startDate: options.startDate,
1577
1711
  endDate: options.endDate,
1578
1712
  payeePayerName: options.payee,
1579
1713
  paymtPurpose: options.purpose,
1714
+ ...page
1715
+ }), {
1580
1716
  limit: options.limit,
1581
- offset: options.offset
1717
+ offset: options.offset,
1718
+ keep: options.unbooked ? (transaction) => transaction.status === "100" : void 0
1582
1719
  });
1583
- if (options.unbooked) transactions = transactions.filter((transaction) => transaction.status === "100");
1584
1720
  if (options.json) {
1585
1721
  printJson(transactions);
1586
1722
  return;
@@ -1673,6 +1809,8 @@ var create_default = defineCommand({
1673
1809
  taxRate: z.coerce.number().default(19).describe("Tax rate of the voucher position in percent."),
1674
1810
  voucherDate: z.string().optional().describe("Date as dd.mm.yyyy or Unix timestamp."),
1675
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."),
1676
1814
  supplierId: z.coerce.number().optional().describe("ID of the supplier contact."),
1677
1815
  supplierName: z.string().optional().describe("Name of the supplier, used when no supplier ID is given."),
1678
1816
  description: z.string().optional().describe("The voucher number."),
@@ -1680,6 +1818,10 @@ var create_default = defineCommand({
1680
1818
  json: z.boolean().default(false).describe("Output in JSON format.")
1681
1819
  })),
1682
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
+ }
1683
1825
  const client = await requireClient();
1684
1826
  const path = await requireStringOption({
1685
1827
  value: options.file,
@@ -1719,6 +1861,8 @@ var create_default = defineCommand({
1719
1861
  taxRuleId,
1720
1862
  voucherDate: options.voucherDate,
1721
1863
  payDate: options.payDate,
1864
+ deliveryDate: options.deliveryDate,
1865
+ deliveryDateUntil: options.deliveryDateUntil,
1722
1866
  supplierId: options.supplierId,
1723
1867
  supplierName,
1724
1868
  description: options.description
@@ -1793,6 +1937,7 @@ var get_default = defineCommand({
1793
1937
  consola.info(`ID: ${voucher.id}`);
1794
1938
  consola.info(`Status: ${voucher.status ?? "-"}`);
1795
1939
  consola.info(`Date: ${voucher.voucherDate ?? "-"}`);
1940
+ consola.info(`Service period: ${servicePeriodLabel(voucher.deliveryDate, voucher.deliveryDateUntil) || "-"}`);
1796
1941
  consola.info(`Supplier: ${voucher.supplierName ?? contactLabel(voucher.supplier)}`);
1797
1942
  consola.info(`Description: ${voucher.description ?? "-"}`);
1798
1943
  consola.info(`Net: ${voucher.sumNet}`);
@@ -1813,21 +1958,24 @@ var list_default = defineCommand({
1813
1958
  startDate: z.string().optional().describe("Only vouchers on or after this date as dd.mm.yyyy or Unix timestamp."),
1814
1959
  endDate: z.string().optional().describe("Only vouchers on or before this date as dd.mm.yyyy or Unix timestamp."),
1815
1960
  contact: z.coerce.number().optional().describe("ID of the contact whose vouchers to list."),
1816
- 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."),
1817
1962
  offset: z.coerce.number().optional().describe("Number of vouchers to skip."),
1818
1963
  json: z.boolean().default(false).describe("Output in JSON format.")
1819
1964
  })),
1820
1965
  action: async (options) => {
1821
- const vouchers = await (await requireClient()).vouchers.list({
1966
+ const client = await requireClient();
1967
+ const vouchers = await fetchAll((page) => client.vouchers.list({
1822
1968
  status: options.status,
1823
1969
  creditDebit: options.creditDebit,
1824
1970
  descriptionLike: options.descriptionLike,
1825
1971
  startDate: options.startDate,
1826
1972
  endDate: options.endDate,
1827
1973
  contactId: options.contact,
1974
+ embed: ["supplier"],
1975
+ ...page
1976
+ }), {
1828
1977
  limit: options.limit,
1829
- offset: options.offset,
1830
- embed: ["supplier"]
1978
+ offset: options.offset
1831
1979
  });
1832
1980
  if (options.json) {
1833
1981
  printJson(vouchers);
@@ -1840,6 +1988,7 @@ var list_default = defineCommand({
1840
1988
  printTable(vouchers.map((voucher) => ({
1841
1989
  id: voucher.id,
1842
1990
  date: voucher.voucherDate ?? "",
1991
+ servicePeriod: servicePeriodLabel(voucher.deliveryDate, voucher.deliveryDateUntil),
1843
1992
  supplier: voucher.supplierName ?? contactLabel(voucher.supplier),
1844
1993
  description: voucher.description ?? "",
1845
1994
  gross: voucher.sumGross,
@@ -1853,16 +2002,19 @@ var positions_default = defineCommand({
1853
2002
  description: "List voucher positions.",
1854
2003
  options: defineOptions(z.object({
1855
2004
  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."),
2005
+ limit: z.coerce.number().optional().describe("Maximum number of positions to return. Defaults to all of them."),
1857
2006
  offset: z.coerce.number().optional().describe("Number of positions to skip."),
1858
2007
  json: z.boolean().default(false).describe("Output in JSON format.")
1859
2008
  })),
1860
2009
  action: async (options) => {
1861
- const positions = await (await requireClient()).vouchers.listPositions({
2010
+ const client = await requireClient();
2011
+ const positions = await fetchAll((page) => client.vouchers.listPositions({
1862
2012
  voucherId: options.voucher,
2013
+ embed: ["accountDatev"],
2014
+ ...page
2015
+ }), {
1863
2016
  limit: options.limit,
1864
- offset: options.offset,
1865
- embed: ["accountDatev"]
2017
+ offset: options.offset
1866
2018
  });
1867
2019
  if (options.json) {
1868
2020
  printJson(positions);
@@ -1958,6 +2110,8 @@ const config = defineConfig({
1958
2110
  login: login_default,
1959
2111
  logout: logout_default,
1960
2112
  doctor: doctor_default,
2113
+ "accounts-datev:get": get_default$8,
2114
+ "accounts-datev:list": list_default$9,
1961
2115
  "accounts:balance": balance_default,
1962
2116
  "accounts:create-clearing": create_clearing_default,
1963
2117
  "accounts:create-file-import": create_file_import_default,