@kevludwig/eve-lexware-office 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/dist/extension/_manifest.json +14 -0
  4. package/dist/extension/extension.d.ts +36 -0
  5. package/dist/extension/extension.mjs +36 -0
  6. package/dist/extension/hooks/approval-cards.d.ts +8 -0
  7. package/dist/extension/hooks/approval-cards.mjs +26 -0
  8. package/dist/extension/hooks/declined-reminders.d.ts +7 -0
  9. package/dist/extension/hooks/declined-reminders.mjs +27 -0
  10. package/dist/extension/instructions.md +16 -0
  11. package/dist/extension/lib/cards.d.ts +8 -0
  12. package/dist/extension/lib/cards.mjs +156 -0
  13. package/dist/extension/lib/findings.d.ts +128 -0
  14. package/dist/extension/lib/findings.mjs +176 -0
  15. package/dist/extension/lib/format.d.ts +3 -0
  16. package/dist/extension/lib/format.mjs +16 -0
  17. package/dist/extension/lib/journal.d.ts +15 -0
  18. package/dist/extension/lib/journal.mjs +27 -0
  19. package/dist/extension/lib/purchase-card.d.ts +3 -0
  20. package/dist/extension/lib/purchase-card.mjs +66 -0
  21. package/dist/extension/lib/purchase.d.ts +112 -0
  22. package/dist/extension/lib/purchase.mjs +346 -0
  23. package/dist/extension/lib/runtime.d.ts +18 -0
  24. package/dist/extension/lib/runtime.mjs +47 -0
  25. package/dist/extension/lib/sales.d.ts +72 -0
  26. package/dist/extension/lib/sales.mjs +292 -0
  27. package/dist/extension/lib/state.d.ts +9 -0
  28. package/dist/extension/lib/state.mjs +44 -0
  29. package/dist/extension/lib/types.d.ts +43 -0
  30. package/dist/extension/lib/types.mjs +7 -0
  31. package/dist/extension/skills/eingangsrechnung/SKILL.md +124 -0
  32. package/dist/extension/skills/verkaufsbelege/SKILL.md +94 -0
  33. package/dist/extension/skills/zahlungserinnerung/SKILL.md +37 -0
  34. package/dist/extension/tools/create_customer.d.ts +44 -0
  35. package/dist/extension/tools/create_customer.mjs +107 -0
  36. package/dist/extension/tools/create_invoice.d.ts +28 -0
  37. package/dist/extension/tools/create_invoice.mjs +28 -0
  38. package/dist/extension/tools/create_order_confirmation.d.ts +28 -0
  39. package/dist/extension/tools/create_order_confirmation.mjs +33 -0
  40. package/dist/extension/tools/create_purchase_invoice.d.ts +76 -0
  41. package/dist/extension/tools/create_purchase_invoice.mjs +241 -0
  42. package/dist/extension/tools/create_quotation.d.ts +28 -0
  43. package/dist/extension/tools/create_quotation.mjs +28 -0
  44. package/dist/extension/tools/due_payment_reminders.d.ts +39 -0
  45. package/dist/extension/tools/due_payment_reminders.mjs +56 -0
  46. package/dist/extension/tools/read.d.ts +10 -0
  47. package/dist/extension/tools/read.mjs +83 -0
  48. package/dist/extension/tools/send_payment_reminder.d.ts +57 -0
  49. package/dist/extension/tools/send_payment_reminder.mjs +180 -0
  50. package/dist/index.d.ts +4 -0
  51. package/dist/index.mjs +8 -0
  52. package/dist/tools/index.d.ts +10 -0
  53. package/dist/tools/index.mjs +15 -0
  54. package/package.json +69 -0
@@ -0,0 +1,39 @@
1
+ /** Which overdue invoices are due for a reminder now — the same rule a scheduled run applies. Reads only. */
2
+ declare const _default: import("eve/tools").ToolDefinition<Record<string, never>, {
3
+ test_mode: boolean;
4
+ due: {
5
+ invoice_id: string;
6
+ voucher_number: string;
7
+ customer_name: string;
8
+ open_amount: number;
9
+ due_date: string;
10
+ days_overdue: number;
11
+ }[];
12
+ not_yet: {
13
+ voucher_number: string;
14
+ customer_name: string;
15
+ open_amount: number;
16
+ reason: string;
17
+ conversation?: string | undefined;
18
+ }[];
19
+ }> & {
20
+ execute(input: Record<string, never>, ctx: import("eve/tools").ToolContext): Promise<{
21
+ test_mode: boolean;
22
+ due: {
23
+ invoice_id: string;
24
+ voucher_number: string;
25
+ customer_name: string;
26
+ open_amount: number;
27
+ due_date: string;
28
+ days_overdue: number;
29
+ }[];
30
+ not_yet: {
31
+ voucher_number: string;
32
+ customer_name: string;
33
+ open_amount: number;
34
+ reason: string;
35
+ conversation?: string | undefined;
36
+ }[];
37
+ }>;
38
+ };
39
+ export default _default;
@@ -0,0 +1,56 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import { shortDate } from "../lib/format.mjs";
8
+ import { client, config, ledger } from "../lib/runtime.mjs";
9
+ import { z } from "zod";
10
+ import { DEFAULT_REMINDER_POLICY, daysSince, selectDueReminders } from "@kevludwig/lexware-office";
11
+ import { defineTool } from "eve/tools";
12
+ function describeHold(hold, immediateTermDays) {
13
+ switch (hold.kind) {
14
+ case "too-early": return hold.immediate ? `sofort fällig — erinnert wird ab ${shortDate(hold.earliest)} (intern ${immediateTermDays} Tage Zahlungsziel, dann Puffer)` : `erinnert wird ab ${shortDate(hold.earliest)}`;
15
+ case "sent": return `schon erinnert am ${shortDate(hold.at)}`;
16
+ case "pending": return `Erinnerung wartet seit ${shortDate(hold.at)} auf Freigabe`;
17
+ case "declined": return `Erinnerung am ${shortDate(hold.at)} abgebrochen — vorerst Ruhe`;
18
+ case "no-address": return "für den Kunden ist keine E-Mail-Adresse hinterlegt";
19
+ case "unreadable": return "Status oder Adresse gerade nicht lesbar — vorsichtshalber ausgelassen";
20
+ }
21
+ }
22
+ var due_payment_reminders_default = defineTool({
23
+ description: "Prüft, zu welchen überfälligen Rechnungen jetzt eine Zahlungserinnerung fällig ist (Puffer nach Fälligkeit, Zahlungsziel bei sofort fälligen Rechnungen, schon erinnert, wartet auf Freigabe, abgebrochen, keine Adresse). `due` enthält je Rechnung genau die Werte für das Tool send_payment_reminder; `not_yet` die übrigen mit Grund. Liest nur.",
24
+ inputSchema: z.object({}).strict(),
25
+ async execute(_input, ctx) {
26
+ const reminders = config().reminders;
27
+ const policy = {
28
+ ...DEFAULT_REMINDER_POLICY,
29
+ ...reminders.policy
30
+ };
31
+ const { due, held } = await selectDueReminders(client(), ledger(), {
32
+ policy,
33
+ signal: ctx.abortSignal
34
+ });
35
+ const link = config().conversationUrl;
36
+ return {
37
+ test_mode: reminders.mode !== "live",
38
+ due: due.map(({ invoice }) => ({
39
+ invoice_id: invoice.id,
40
+ voucher_number: invoice.voucherNumber,
41
+ customer_name: invoice.contactName,
42
+ open_amount: invoice.openAmount,
43
+ due_date: invoice.dueDate,
44
+ days_overdue: daysSince(invoice.dueDate)
45
+ })),
46
+ not_yet: held.map(({ invoice, hold }) => ({
47
+ voucher_number: invoice.voucherNumber,
48
+ customer_name: invoice.contactName,
49
+ open_amount: invoice.openAmount,
50
+ reason: describeHold(hold, policy.immediatePaymentTermDays),
51
+ ...hold.kind === "pending" && hold.sessionId && link ? { conversation: link(hold.sessionId) } : {}
52
+ }))
53
+ };
54
+ }
55
+ });
56
+ export { due_payment_reminders_default as default };
@@ -0,0 +1,10 @@
1
+ declare const _default: import("eve/tools").ToolDefinition<{
2
+ path: string;
3
+ query?: Record<string, string | number | boolean> | undefined;
4
+ }, unknown> & {
5
+ execute(input: {
6
+ path: string;
7
+ query?: Record<string, string | number | boolean> | undefined;
8
+ }, ctx: import("eve/tools").ToolContext): Promise<unknown>;
9
+ };
10
+ export default _default;
@@ -0,0 +1,83 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import { client } from "../lib/runtime.mjs";
8
+ import { z } from "zod";
9
+ import { describeError, query } from "@kevludwig/lexware-office";
10
+ import { defineTool } from "eve/tools";
11
+ const UUID = "[0-9a-fA-F-]{36}";
12
+ const READABLE = [
13
+ new RegExp(`^/contacts(/${UUID})?$`),
14
+ new RegExp(`^/articles(/${UUID})?$`),
15
+ new RegExp(`^/vouchers/${UUID}$`),
16
+ /^\/voucherlist$/,
17
+ new RegExp(`^/invoices/${UUID}$`),
18
+ new RegExp(`^/credit-notes/${UUID}$`),
19
+ new RegExp(`^/delivery-notes/${UUID}$`),
20
+ new RegExp(`^/down-payment-invoices/${UUID}$`),
21
+ new RegExp(`^/dunnings/${UUID}$`),
22
+ new RegExp(`^/order-confirmations/${UUID}$`),
23
+ new RegExp(`^/quotations/${UUID}$`),
24
+ new RegExp(`^/payments/${UUID}$`),
25
+ new RegExp(`^/recurring-templates(/${UUID})?$`),
26
+ new RegExp(`^/event-subscriptions(/${UUID})?$`),
27
+ new RegExp(`^/files/${UUID}/status$`),
28
+ /^\/posting-categories$/,
29
+ /^\/payment-conditions$/,
30
+ /^\/print-layouts$/,
31
+ /^\/countries$/,
32
+ /^\/profile$/
33
+ ];
34
+ const MAX_LIST_CHARS = 12e3;
35
+ const MAX_DOCUMENT_CHARS = 6e4;
36
+ var read_default = defineTool({
37
+ description: "Liest Daten aus Lexware Office: Kontakte, Artikel, Belegliste, einzelne Belege, Buchungskategorien, Zahlungsbedingungen, Profil, Länder. Nur lesend. Nützlich, um eine Kundennummer aufzulösen, eine Buchungskategorie zu finden oder zu prüfen, ob ein Beleg schon existiert.",
38
+ inputSchema: z.object({
39
+ path: z.string().trim().min(2).max(200).describe("Pfad ohne Basis-URL, z.B. '/contacts', '/voucherlist' oder '/posting-categories'. Nur lesende Endpunkte."),
40
+ query: z.record(z.string(), z.union([
41
+ z.string(),
42
+ z.number(),
43
+ z.boolean()
44
+ ])).optional().describe("Query-Parameter, z.B. { number: 10001 } für /contacts oder { voucherType: 'invoice', voucherStatus: 'overdue' } für /voucherlist — dort sind voucherType und voucherStatus Pflicht.")
45
+ }).strict(),
46
+ async execute(input, ctx) {
47
+ const path = input.path.startsWith("/") ? input.path : `/${input.path}`;
48
+ if (path.includes("?")) return { error: `Query-Parameter gehören in das Feld \`query\`, nicht in den Pfad (${path}).` };
49
+ if (!READABLE.some((pattern) => pattern.test(path))) return { error: `${path} ist über dieses Tool nicht lesbar. Lesbar sind: /contacts, /articles, /voucherlist, /vouchers/{id}, /invoices/{id}, /credit-notes/{id}, /delivery-notes/{id}, /down-payment-invoices/{id}, /dunnings/{id}, /order-confirmations/{id}, /quotations/{id}, /payments/{id}, /recurring-templates, /event-subscriptions, /files/{id}/status, /posting-categories, /payment-conditions, /print-layouts, /countries, /profile.` };
50
+ try {
51
+ return truncate(await client().request(`${path}${query(input.query ?? {})}`, { signal: ctx.abortSignal }));
52
+ } catch (error) {
53
+ return { error: describeError(error) };
54
+ }
55
+ }
56
+ });
57
+ function truncate(data) {
58
+ const rendered = JSON.stringify(data) ?? "";
59
+ const isList = Boolean(data && typeof data === "object" && Array.isArray(data.content));
60
+ const max = isList ? MAX_LIST_CHARS : MAX_DOCUMENT_CHARS;
61
+ if (rendered.length <= max) return data;
62
+ if (isList) {
63
+ const page = data;
64
+ const kept = [];
65
+ let size = 0;
66
+ for (const entry of page.content) {
67
+ const length = (JSON.stringify(entry) ?? "").length + 1;
68
+ if (size + length > max) break;
69
+ kept.push(entry);
70
+ size += length;
71
+ }
72
+ return {
73
+ ...page,
74
+ content: kept,
75
+ _truncated: `Nur ${kept.length} von ${page.content.length} Einträgen gezeigt. Grenze über die Query-Parameter ein (size, voucherDateFrom).`
76
+ };
77
+ }
78
+ return {
79
+ _truncated: `Antwort auf ${max} Zeichen gekürzt.`,
80
+ data: rendered.slice(0, max)
81
+ };
82
+ }
83
+ export { read_default as default };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * A friendly payment reminder by mail, with the invoice PDF attached. The
3
+ * text comes from the mount's template, the recipient from Lexware Office and
4
+ * the mode — never from the model. Sent at most once per invoice and round.
5
+ */
6
+ declare const _default: import("eve/tools").ToolDefinition<{
7
+ invoice_id: string;
8
+ voucher_number: string;
9
+ customer_name: string;
10
+ open_amount: number;
11
+ due_date: string;
12
+ }, {
13
+ sent: boolean;
14
+ note: string;
15
+ to?: undefined;
16
+ cc?: undefined;
17
+ test?: undefined;
18
+ invoice?: undefined;
19
+ openAmount?: undefined;
20
+ attachment?: undefined;
21
+ } | {
22
+ sent: boolean;
23
+ to: string;
24
+ cc: readonly string[];
25
+ test: boolean;
26
+ invoice: string;
27
+ openAmount: number;
28
+ attachment: string;
29
+ note: string;
30
+ }> & {
31
+ execute(input: {
32
+ invoice_id: string;
33
+ voucher_number: string;
34
+ customer_name: string;
35
+ open_amount: number;
36
+ due_date: string;
37
+ }, ctx: import("eve/tools").ToolContext): Promise<{
38
+ sent: boolean;
39
+ note: string;
40
+ to?: undefined;
41
+ cc?: undefined;
42
+ test?: undefined;
43
+ invoice?: undefined;
44
+ openAmount?: undefined;
45
+ attachment?: undefined;
46
+ } | {
47
+ sent: boolean;
48
+ to: string;
49
+ cc: readonly string[];
50
+ test: boolean;
51
+ invoice: string;
52
+ openAmount: number;
53
+ attachment: string;
54
+ note: string;
55
+ }>;
56
+ };
57
+ export default _default;
@@ -0,0 +1,180 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import { shortDate } from "../lib/format.mjs";
8
+ import { approverPolicy, client, config, ledger, renderReminder } from "../lib/runtime.mjs";
9
+ import { saveWarnings } from "../lib/findings.mjs";
10
+ import { readJournal, writeJournal } from "../lib/journal.mjs";
11
+ import { bindReminderTarget, boundReminderTarget } from "../lib/state.mjs";
12
+ import { z } from "zod";
13
+ import { DEFAULT_REMINDER_POLICY, contactEmail, daysPastReminderDue, daysSince, describeError, earliestReminderDate, findOverdueInvoice, isDueImmediately, sendReminder } from "@kevludwig/lexware-office";
14
+ import { defineTool } from "eve/tools";
15
+ const inputSchema = z.object({
16
+ invoice_id: z.string().uuid().describe("Id der überfälligen Rechnung in Lexware Office"),
17
+ voucher_number: z.string().trim().min(1).max(50).describe("Rechnungsnummer, z.B. RE20260192"),
18
+ customer_name: z.string().trim().min(1).max(255).describe("Kunde laut Lexware Office"),
19
+ open_amount: z.number().positive().describe("Offener Betrag laut Lexware Office"),
20
+ due_date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Fälligkeitsdatum yyyy-MM-dd laut Lexware Office")
21
+ }).strict();
22
+ const sameName = (a, b) => a !== void 0 && a.replace(/\s+/g, " ").trim() === b.replace(/\s+/g, " ").trim();
23
+ var send_payment_reminder_default = defineTool({
24
+ description: "Schickt eine freundliche Zahlungserinnerung zu einer überfälligen Rechnung per E-Mail, mit der Rechnung als PDF im Anhang. Die Werte (Nummer, Kunde, offener Betrag, Fälligkeit) übernimmst du unverändert aus Lexware Office bzw. aus dem Tool due_payment_reminders — dieses Tool prüft sie. Der Text ist fest vorgegeben. Verschickt wird erst nach Freigabe.",
25
+ inputSchema,
26
+ approval: {
27
+ request: async (ctx) => {
28
+ const input = ctx.toolInput;
29
+ if (!input?.invoice_id) return "user-approval";
30
+ const reminders = config().reminders;
31
+ const policy = {
32
+ ...DEFAULT_REMINDER_POLICY,
33
+ ...reminders.policy
34
+ };
35
+ let invoice;
36
+ try {
37
+ invoice = await findOverdueInvoice(client(), input.invoice_id, ctx.abortSignal);
38
+ } catch (error) {
39
+ return {
40
+ type: "denied",
41
+ reason: `Lexware Office nicht erreichbar (${describeError(error)}). Später erneut versuchen.`
42
+ };
43
+ }
44
+ if (!invoice) return {
45
+ type: "denied",
46
+ reason: `Rechnung ${input.voucher_number ?? input.invoice_id} ist nicht (mehr) überfällig — keine Erinnerung nötig.`
47
+ };
48
+ const mismatches = [
49
+ input.voucher_number !== invoice.voucherNumber && `Rechnungsnummer ${invoice.voucherNumber}`,
50
+ Math.abs((input.open_amount ?? 0) - invoice.openAmount) > .01 && `offener Betrag ${invoice.openAmount}`,
51
+ input.due_date !== invoice.dueDate && `Fälligkeit ${invoice.dueDate}`,
52
+ !sameName(input.customer_name, invoice.contactName) && `Kunde „${invoice.contactName}“`
53
+ ].filter(Boolean);
54
+ if (mismatches.length > 0) return {
55
+ type: "denied",
56
+ reason: `Die Angaben passen nicht zu Lexware Office. Richtig ist: ${mismatches.join(", ")}. Rufe das Tool mit diesen Werten erneut auf.`
57
+ };
58
+ let customer = null;
59
+ if (invoice.contactId) try {
60
+ customer = await contactEmail(client(), invoice.contactId, ctx.abortSignal);
61
+ } catch (error) {
62
+ console.warn(`[lexware] Customer address not readable: ${describeError(error)}`);
63
+ }
64
+ const live = reminders.mode === "live";
65
+ const to = live ? customer : reminders.ownerEmail ?? null;
66
+ if (!to) return {
67
+ type: "denied",
68
+ reason: live ? `Für ${invoice.contactName} ist keine E-Mail-Adresse hinterlegt — keine Erinnerung möglich. Melde das dem Nutzer.` : "Im Testmodus fehlt reminders.ownerEmail — kein Testversand möglich. Melde das dem Nutzer."
69
+ };
70
+ const cc = live && reminders.ccOwner && reminders.ownerEmail && reminders.ownerEmail !== to ? [reminders.ownerEmail] : [];
71
+ let earlier;
72
+ try {
73
+ earlier = await ledger().read(invoice.id);
74
+ } catch (error) {
75
+ return {
76
+ type: "denied",
77
+ reason: `Ob zu ${invoice.voucherNumber} schon erinnert wurde, ist gerade nicht lesbar. Später erneut versuchen.`
78
+ };
79
+ }
80
+ const findings = [live ? {
81
+ kind: "note",
82
+ title: "Empfänger",
83
+ value: cc.length ? `${to}, Cc ${cc.join(", ")}` : to
84
+ } : {
85
+ kind: "note",
86
+ title: "Testmodus",
87
+ value: `Geht an ${to}, nicht an den Kunden (im Echtbetrieb: ${customer ?? "keine Adresse hinterlegt"})`
88
+ }];
89
+ if (daysPastReminderDue(invoice, policy) < policy.minDaysOverdue) findings.push({
90
+ kind: "note",
91
+ title: "⚠ Früh",
92
+ value: isDueImmediately(invoice) ? `Sofort fällig, erinnert wird sonst erst ab ${shortDate(earliestReminderDate(invoice, policy))}` : `Erst ${daysSince(invoice.dueDate)} Tage überfällig — erinnert wird sonst ab ${shortDate(earliestReminderDate(invoice, policy))}`
93
+ });
94
+ if (earlier?.status === "sent") findings.push({
95
+ kind: "note",
96
+ title: "⚠ Schon erinnert",
97
+ value: `Am ${shortDate(earlier.at)} ging bereits eine Erinnerung raus${earlier.recipient ? ` an ${earlier.recipient}` : ""}`
98
+ });
99
+ if (earlier?.status === "pending" && earlier.sessionId && earlier.sessionId !== ctx.session.id) {
100
+ const link = config().conversationUrl?.(earlier.sessionId);
101
+ findings.push({
102
+ kind: "note",
103
+ title: "⚠ Wartet schon",
104
+ value: `Eine Erinnerung wartet seit ${shortDate(earlier.at)} in einer anderen Unterhaltung${link ? ` (${link})` : ""} — verschickt wird höchstens eine`
105
+ });
106
+ }
107
+ if (!reminders.sendMail) findings.push({
108
+ kind: "note",
109
+ title: "⚠ Mailversand fehlt",
110
+ value: "Ohne reminders.sendMail wird nichts verschickt."
111
+ });
112
+ saveWarnings(ctx.callId, findings);
113
+ bindReminderTarget(ctx.callId, {
114
+ invoiceId: invoice.id,
115
+ voucherNumber: invoice.voucherNumber,
116
+ voucherDate: invoice.voucherDate,
117
+ dueDate: invoice.dueDate,
118
+ currency: invoice.currency,
119
+ to,
120
+ cc,
121
+ test: !live,
122
+ customer,
123
+ earlierSentAt: earlier?.status === "sent" ? earlier.at : void 0
124
+ });
125
+ if (earlier?.status !== "sent") await ledger().markPending(invoice, ctx.session.id).catch(() => {});
126
+ return "user-approval";
127
+ },
128
+ response: approverPolicy
129
+ },
130
+ async execute(_input, ctx) {
131
+ const target = boundReminderTarget(ctx.callId);
132
+ if (!target) throw new Error("Abgebrochen: Die an die Freigabe gebundenen Angaben fehlen — nichts verschickt.");
133
+ const sendMail = config().reminders.sendMail;
134
+ if (!sendMail) throw new Error("Abgebrochen: Der Mailversand ist nicht eingerichtet (reminders.sendMail) — nichts verschickt.");
135
+ const journal = await readJournal("reminder", ctx.callId);
136
+ if (journal) {
137
+ if (journal.status === "created") await ledger().write({
138
+ invoiceId: target.invoiceId,
139
+ voucherNumber: target.voucherNumber,
140
+ status: "sent",
141
+ recipient: target.to,
142
+ sessionId: ctx.session.id
143
+ }).catch(() => {});
144
+ return journal.status === "created" ? {
145
+ sent: true,
146
+ note: "Wiederaufnahme: Die Erinnerung war bereits verschickt."
147
+ } : {
148
+ sent: false,
149
+ note: "Wiederaufnahme nach Abbruch: Ob die Erinnerung rausging, ist unklar. Im Postausgang nachsehen."
150
+ };
151
+ }
152
+ await writeJournal("reminder", ctx.callId, { status: "pending" });
153
+ const outcome = await sendReminder(client(), ledger(), target, {
154
+ render: renderReminder(),
155
+ sendMail,
156
+ owner: ctx.callId,
157
+ sessionId: ctx.session.id,
158
+ signal: ctx.abortSignal
159
+ });
160
+ if (!outcome.sent) return {
161
+ sent: false,
162
+ note: outcome.reason === "paid" ? `Rechnung ${target.voucherNumber} ist inzwischen nicht mehr überfällig — nichts verschickt.` : `Zu ${target.voucherNumber} ist über eine andere Freigabe schon eine Erinnerung rausgegangen oder unterwegs — nichts verschickt.`
163
+ };
164
+ await writeJournal("reminder", ctx.callId, {
165
+ status: "created",
166
+ resourceId: target.invoiceId
167
+ });
168
+ return {
169
+ sent: true,
170
+ to: target.to,
171
+ cc: target.cc ?? [],
172
+ test: target.test,
173
+ invoice: target.voucherNumber,
174
+ openAmount: outcome.openAmount,
175
+ attachment: outcome.attachment,
176
+ note: target.test ? `Testversand an ${target.to}. Im Echtbetrieb ginge die Erinnerung an ${target.customer ?? "den Kunden (keine Adresse hinterlegt)"}.` : `Erinnerung an ${target.to} verschickt.`
177
+ };
178
+ }
179
+ });
180
+ export { send_payment_reminder_default as default };
@@ -0,0 +1,4 @@
1
+ // Generated by eve. Do not edit by hand.
2
+
3
+ export { default } from "./extension/extension.js";
4
+ export { default as eve_lexware_office } from "./extension/extension.js";
package/dist/index.mjs ADDED
@@ -0,0 +1,8 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import extension_default from "./extension/extension.mjs";
8
+ export { extension_default as default, extension_default as eve_lexware_office };
@@ -0,0 +1,10 @@
1
+ // Generated by eve. Do not edit by hand.
2
+
3
+ export { default as create_customer } from "../extension/tools/create_customer.js";
4
+ export { default as create_invoice } from "../extension/tools/create_invoice.js";
5
+ export { default as create_order_confirmation } from "../extension/tools/create_order_confirmation.js";
6
+ export { default as create_purchase_invoice } from "../extension/tools/create_purchase_invoice.js";
7
+ export { default as create_quotation } from "../extension/tools/create_quotation.js";
8
+ export { default as due_payment_reminders } from "../extension/tools/due_payment_reminders.js";
9
+ export { default as read } from "../extension/tools/read.js";
10
+ export { default as send_payment_reminder } from "../extension/tools/send_payment_reminder.js";
@@ -0,0 +1,15 @@
1
+ import { fileURLToPath as __eveFileURLToPath } from "node:url";
2
+ import { dirname as __eveDirname } from "node:path";
3
+ import { createRequire as __eveCreateRequire } from "node:module";
4
+ const __filename = __eveFileURLToPath(import.meta.url);
5
+ __eveDirname(__filename);
6
+ __eveCreateRequire(import.meta.url);
7
+ import create_customer_default from "../extension/tools/create_customer.mjs";
8
+ import create_invoice_default from "../extension/tools/create_invoice.mjs";
9
+ import create_order_confirmation_default from "../extension/tools/create_order_confirmation.mjs";
10
+ import create_purchase_invoice_default from "../extension/tools/create_purchase_invoice.mjs";
11
+ import create_quotation_default from "../extension/tools/create_quotation.mjs";
12
+ import due_payment_reminders_default from "../extension/tools/due_payment_reminders.mjs";
13
+ import read_default from "../extension/tools/read.mjs";
14
+ import send_payment_reminder_default from "../extension/tools/send_payment_reminder.mjs";
15
+ export { create_customer_default as create_customer, create_invoice_default as create_invoice, create_order_confirmation_default as create_order_confirmation, create_purchase_invoice_default as create_purchase_invoice, create_quotation_default as create_quotation, due_payment_reminders_default as due_payment_reminders, read_default as read, send_payment_reminder_default as send_payment_reminder };
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@kevludwig/eve-lexware-office",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "eve": {
6
+ "extension": {
7
+ "source": "./extension",
8
+ "dist": "./dist/extension"
9
+ }
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.mjs"
18
+ },
19
+ "./tools": {
20
+ "types": "./dist/tools/index.d.ts",
21
+ "default": "./dist/tools/index.mjs"
22
+ }
23
+ },
24
+ "dependencies": {
25
+ "@vercel/blob": "^2.8.0",
26
+ "zod": "4.5.4",
27
+ "@kevludwig/lexware-office": "0.1.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "24.x",
31
+ "eve": "0.63.0",
32
+ "typescript": "7.0.2"
33
+ },
34
+ "peerDependencies": {
35
+ "eve": "*"
36
+ },
37
+ "description": "eve extension for Lexware Office: read the account, create customers, quotations, order confirmations, invoices and purchase invoices, and send payment reminders — every write behind an approval.",
38
+ "license": "MIT",
39
+ "author": "Kevin Ludwig",
40
+ "keywords": [
41
+ "eve",
42
+ "eve-extension",
43
+ "agent",
44
+ "lexware",
45
+ "lexware-office",
46
+ "lexoffice"
47
+ ],
48
+ "engines": {
49
+ "node": ">=24"
50
+ },
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "git+https://github.com/kevludwig/eve-lexware-office.git",
54
+ "directory": "packages/eve-lexware-office"
55
+ },
56
+ "homepage": "https://github.com/kevludwig/eve-lexware-office/tree/main/packages/eve-lexware-office#readme",
57
+ "bugs": {
58
+ "url": "https://github.com/kevludwig/eve-lexware-office/issues"
59
+ },
60
+ "publishConfig": {
61
+ "access": "public"
62
+ },
63
+ "scripts": {
64
+ "build": "eve extension build",
65
+ "typecheck": "tsc",
66
+ "pretest": "eve extension build",
67
+ "test": "node --test --experimental-test-module-mocks test/*.test.ts"
68
+ }
69
+ }