@dizzlkheinz/ynab-mcpb 0.18.3 → 0.18.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/CHANGELOG.md +17 -0
- package/dist/bundle/index.cjs +40 -40
- package/dist/tools/reconcileAdapter.js +3 -0
- package/dist/tools/reconciliation/analyzer.js +72 -7
- package/dist/tools/reconciliation/reportFormatter.js +26 -2
- package/dist/tools/reconciliation/types.d.ts +3 -0
- package/dist/tools/transactionSchemas.d.ts +309 -0
- package/dist/tools/transactionSchemas.js +215 -0
- package/dist/tools/transactionTools.d.ts +3 -281
- package/dist/tools/transactionTools.js +4 -559
- package/dist/tools/transactionUtils.d.ts +31 -0
- package/dist/tools/transactionUtils.js +349 -0
- package/docs/plans/2025-12-25-transaction-tools-refactor-design.md +211 -0
- package/docs/plans/2025-12-25-transaction-tools-refactor.md +905 -0
- package/package.json +4 -2
- package/scripts/run-all-tests.js +196 -0
- package/src/tools/__tests__/transactionSchemas.test.ts +1188 -0
- package/src/tools/__tests__/transactionUtils.test.ts +989 -0
- package/src/tools/reconcileAdapter.ts +6 -0
- package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +22 -8
- package/src/tools/reconciliation/__tests__/adapter.test.ts +3 -0
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +65 -0
- package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +3 -0
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +4 -1
- package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +3 -0
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +5 -1
- package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +22 -8
- package/src/tools/reconciliation/analyzer.ts +127 -11
- package/src/tools/reconciliation/reportFormatter.ts +39 -2
- package/src/tools/reconciliation/types.ts +6 -0
- package/src/tools/transactionSchemas.ts +453 -0
- package/src/tools/transactionTools.ts +102 -823
- package/src/tools/transactionUtils.ts +536 -0
|
@@ -38,6 +38,8 @@ const convertSummary = (analysis) => ({
|
|
|
38
38
|
statement_date_range: analysis.summary.statement_date_range,
|
|
39
39
|
bank_transactions_count: analysis.summary.bank_transactions_count,
|
|
40
40
|
ynab_transactions_count: analysis.summary.ynab_transactions_count,
|
|
41
|
+
ynab_in_range_count: analysis.summary.ynab_in_range_count ?? analysis.summary.ynab_transactions_count,
|
|
42
|
+
ynab_outside_range_count: analysis.summary.ynab_outside_range_count ?? 0,
|
|
41
43
|
auto_matched: analysis.summary.auto_matched,
|
|
42
44
|
suggested_matches: analysis.summary.suggested_matches,
|
|
43
45
|
unmatched_bank: analysis.summary.unmatched_bank,
|
|
@@ -152,6 +154,7 @@ export const buildReconciliationPayload = (analysis, options = {}, execution) =>
|
|
|
152
154
|
unmatched: {
|
|
153
155
|
bank: analysis.unmatched_bank.map((txn) => toBankTransactionView(txn, currency)),
|
|
154
156
|
ynab: analysis.unmatched_ynab.map((txn) => toYNABTransactionView(txn, currency)),
|
|
157
|
+
ynab_outside_date_range: (analysis.ynab_outside_date_range ?? []).map((txn) => toYNABTransactionView(txn, currency)),
|
|
155
158
|
},
|
|
156
159
|
};
|
|
157
160
|
if (analysis.recommendations && analysis.recommendations.length > 0) {
|
|
@@ -3,6 +3,54 @@ import { findMatches, normalizeConfig, DEFAULT_CONFIG } from './matcher.js';
|
|
|
3
3
|
import { normalizeYNABTransactions } from './ynabAdapter.js';
|
|
4
4
|
import { toMoneyValue } from '../../utils/money.js';
|
|
5
5
|
import { generateRecommendations } from './recommendationEngine.js';
|
|
6
|
+
function calculateDateRange(bankTransactions) {
|
|
7
|
+
if (bankTransactions.length === 0) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const dates = bankTransactions
|
|
11
|
+
.map((t) => t.date)
|
|
12
|
+
.filter((d) => d && /^\d{4}-\d{2}-\d{2}$/.test(d))
|
|
13
|
+
.sort();
|
|
14
|
+
if (dates.length === 0) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
minDate: dates[0],
|
|
19
|
+
maxDate: dates[dates.length - 1],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function filterByDateRange(ynabTransactions, dateRange, dateToleranceDays = 7) {
|
|
23
|
+
if (dateToleranceDays < 0) {
|
|
24
|
+
console.warn(`[filterByDateRange] dateToleranceDays must be non-negative, got ${dateToleranceDays}. Using 0.`);
|
|
25
|
+
dateToleranceDays = 0;
|
|
26
|
+
}
|
|
27
|
+
const inRange = [];
|
|
28
|
+
const outsideRange = [];
|
|
29
|
+
const minParts = dateRange.minDate.split('-').map(Number);
|
|
30
|
+
const maxParts = dateRange.maxDate.split('-').map(Number);
|
|
31
|
+
if (minParts.length !== 3 ||
|
|
32
|
+
maxParts.length !== 3 ||
|
|
33
|
+
minParts.some((n) => !Number.isFinite(n)) ||
|
|
34
|
+
maxParts.some((n) => !Number.isFinite(n))) {
|
|
35
|
+
console.warn(`[filterByDateRange] Invalid date format in range: ${dateRange.minDate} to ${dateRange.maxDate} - returning all transactions`);
|
|
36
|
+
return { inRange: ynabTransactions, outsideRange: [] };
|
|
37
|
+
}
|
|
38
|
+
const [minYear, minMonth, minDay] = minParts;
|
|
39
|
+
const [maxYear, maxMonth, maxDay] = maxParts;
|
|
40
|
+
const minDateWithBuffer = new Date(Date.UTC(minYear, minMonth - 1, minDay - dateToleranceDays));
|
|
41
|
+
const minDateStr = minDateWithBuffer.toISOString().split('T')[0];
|
|
42
|
+
const maxDateWithBuffer = new Date(Date.UTC(maxYear, maxMonth - 1, maxDay + dateToleranceDays));
|
|
43
|
+
const maxDateStr = maxDateWithBuffer.toISOString().split('T')[0];
|
|
44
|
+
for (const txn of ynabTransactions) {
|
|
45
|
+
if (txn.date >= minDateStr && txn.date <= maxDateStr) {
|
|
46
|
+
inRange.push(txn);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
outsideRange.push(txn);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { inRange, outsideRange };
|
|
53
|
+
}
|
|
6
54
|
function mapToTransactionMatch(result) {
|
|
7
55
|
const candidates = result.candidates.map((c) => ({
|
|
8
56
|
ynab_transaction: c.ynabTransaction,
|
|
@@ -55,9 +103,10 @@ function calculateBalances(ynabTransactions, statementBalanceDecimal, currency,
|
|
|
55
103
|
on_track: Math.abs(discrepancy) < 10,
|
|
56
104
|
};
|
|
57
105
|
}
|
|
58
|
-
function generateSummary(bankTransactions,
|
|
106
|
+
function generateSummary(bankTransactions, ynabTransactionsInRange, ynabTransactionsOutsideRange, autoMatches, suggestedMatches, unmatchedBank, unmatchedYNAB, balances) {
|
|
59
107
|
const dates = bankTransactions.map((t) => t.date).sort();
|
|
60
108
|
const dateRange = dates.length > 0 ? `${dates[0]} to ${dates[dates.length - 1]}` : 'Unknown';
|
|
109
|
+
const totalYnabCount = ynabTransactionsInRange.length + ynabTransactionsOutsideRange.length;
|
|
61
110
|
let discrepancyExplanation = '';
|
|
62
111
|
if (balances.on_track) {
|
|
63
112
|
discrepancyExplanation = 'Cleared balance matches statement';
|
|
@@ -79,7 +128,9 @@ function generateSummary(bankTransactions, ynabTransactions, autoMatches, sugges
|
|
|
79
128
|
return {
|
|
80
129
|
statement_date_range: dateRange,
|
|
81
130
|
bank_transactions_count: bankTransactions.length,
|
|
82
|
-
ynab_transactions_count:
|
|
131
|
+
ynab_transactions_count: totalYnabCount,
|
|
132
|
+
ynab_in_range_count: ynabTransactionsInRange.length,
|
|
133
|
+
ynab_outside_range_count: ynabTransactionsOutsideRange.length,
|
|
83
134
|
auto_matched: autoMatches.length,
|
|
84
135
|
suggested_matches: suggestedMatches.length,
|
|
85
136
|
unmatched_bank: unmatchedBank.length,
|
|
@@ -236,9 +287,22 @@ export function analyzeReconciliation(csvContentOrParsed, _csvFilePath, ynabTran
|
|
|
236
287
|
const newBankTransactions = parseResult.transactions;
|
|
237
288
|
const csvParseErrors = parseResult.errors;
|
|
238
289
|
const csvParseWarnings = parseResult.warnings;
|
|
239
|
-
const
|
|
290
|
+
const allYNABTransactions = normalizeYNABTransactions(ynabTransactions);
|
|
291
|
+
const csvDateRange = calculateDateRange(newBankTransactions);
|
|
292
|
+
let ynabInRange;
|
|
293
|
+
let ynabOutsideRange;
|
|
294
|
+
if (csvDateRange) {
|
|
295
|
+
const dateToleranceDays = config.dateToleranceDays ?? 7;
|
|
296
|
+
const filtered = filterByDateRange(allYNABTransactions, csvDateRange, dateToleranceDays);
|
|
297
|
+
ynabInRange = filtered.inRange;
|
|
298
|
+
ynabOutsideRange = filtered.outsideRange;
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
ynabInRange = allYNABTransactions;
|
|
302
|
+
ynabOutsideRange = [];
|
|
303
|
+
}
|
|
240
304
|
const normalizedConfig = normalizeConfig(config);
|
|
241
|
-
const newMatches = findMatches(newBankTransactions,
|
|
305
|
+
const newMatches = findMatches(newBankTransactions, ynabInRange, normalizedConfig);
|
|
242
306
|
const matches = newMatches.map(mapToTransactionMatch);
|
|
243
307
|
const autoMatches = matches.filter((m) => m.confidence === 'high');
|
|
244
308
|
const autoMatchedYnabIds = new Set();
|
|
@@ -255,9 +319,9 @@ export function analyzeReconciliation(csvContentOrParsed, _csvFilePath, ynabTran
|
|
|
255
319
|
if (m.ynabTransaction)
|
|
256
320
|
matchedYnabIds.add(m.ynabTransaction.id);
|
|
257
321
|
});
|
|
258
|
-
const unmatchedYNAB =
|
|
259
|
-
const balances = calculateBalances(
|
|
260
|
-
const summary = generateSummary(matches.map((m) => m.bankTransaction),
|
|
322
|
+
const unmatchedYNAB = ynabInRange.filter((t) => !matchedYnabIds.has(t.id));
|
|
323
|
+
const balances = calculateBalances(allYNABTransactions, statementBalance, currency, accountSnapshot);
|
|
324
|
+
const summary = generateSummary(matches.map((m) => m.bankTransaction), ynabInRange, ynabOutsideRange, autoMatches, suggestedMatches, unmatchedBank, unmatchedYNAB, balances);
|
|
261
325
|
const nextSteps = generateNextSteps(summary);
|
|
262
326
|
const insights = detectInsights(unmatchedBank, summary, balances, currency, csvParseErrors, csvParseWarnings);
|
|
263
327
|
const analysis = {
|
|
@@ -268,6 +332,7 @@ export function analyzeReconciliation(csvContentOrParsed, _csvFilePath, ynabTran
|
|
|
268
332
|
suggested_matches: suggestedMatches,
|
|
269
333
|
unmatched_bank: unmatchedBank,
|
|
270
334
|
unmatched_ynab: unmatchedYNAB,
|
|
335
|
+
ynab_outside_date_range: ynabOutsideRange,
|
|
271
336
|
balance_info: balances,
|
|
272
337
|
next_steps: nextSteps,
|
|
273
338
|
insights,
|
|
@@ -59,13 +59,20 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
59
59
|
lines.push('Transaction Analysis');
|
|
60
60
|
lines.push(SECTION_DIVIDER);
|
|
61
61
|
const summary = analysis.summary;
|
|
62
|
+
const outsideRangeCount = summary.ynab_outside_range_count ?? 0;
|
|
63
|
+
if (outsideRangeCount > 0) {
|
|
64
|
+
const inRangeCount = summary.ynab_in_range_count ?? summary.ynab_transactions_count;
|
|
65
|
+
lines.push(`Comparing ${summary.bank_transactions_count} bank transactions with ${inRangeCount} YNAB transactions within statement period.`);
|
|
66
|
+
lines.push(`(${outsideRangeCount} YNAB transactions outside statement period - not compared)`);
|
|
67
|
+
lines.push('');
|
|
68
|
+
}
|
|
62
69
|
lines.push(`- Automatically matched: ${summary.auto_matched} of ${summary.bank_transactions_count} transactions`);
|
|
63
70
|
lines.push(`- Suggested matches: ${summary.suggested_matches}`);
|
|
64
71
|
lines.push(`- Unmatched bank: ${summary.unmatched_bank}`);
|
|
65
72
|
lines.push(`- Unmatched YNAB: ${summary.unmatched_ynab}`);
|
|
66
73
|
if (analysis.unmatched_bank.length > 0) {
|
|
67
74
|
lines.push('');
|
|
68
|
-
lines.push('
|
|
75
|
+
lines.push('Missing from YNAB (bank transactions without matches):');
|
|
69
76
|
const maxToShow = options.maxUnmatchedToShow ?? 5;
|
|
70
77
|
const toShow = analysis.unmatched_bank.slice(0, maxToShow);
|
|
71
78
|
for (const txn of toShow) {
|
|
@@ -75,9 +82,21 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
75
82
|
lines.push(` ... and ${analysis.unmatched_bank.length - maxToShow} more`);
|
|
76
83
|
}
|
|
77
84
|
}
|
|
85
|
+
if (analysis.unmatched_ynab.length > 0) {
|
|
86
|
+
lines.push('');
|
|
87
|
+
lines.push('Missing from bank statement (YNAB transactions without matches):');
|
|
88
|
+
const maxToShow = options.maxUnmatchedToShow ?? 5;
|
|
89
|
+
const toShow = analysis.unmatched_ynab.slice(0, maxToShow);
|
|
90
|
+
for (const txn of toShow) {
|
|
91
|
+
lines.push(formatYnabTransactionLine(txn));
|
|
92
|
+
}
|
|
93
|
+
if (analysis.unmatched_ynab.length > maxToShow) {
|
|
94
|
+
lines.push(` ... and ${analysis.unmatched_ynab.length - maxToShow} more`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
78
97
|
if (analysis.suggested_matches.length > 0) {
|
|
79
98
|
lines.push('');
|
|
80
|
-
lines.push('Suggested matches:');
|
|
99
|
+
lines.push('Suggested matches (review manually):');
|
|
81
100
|
const maxToShow = options.maxUnmatchedToShow ?? 3;
|
|
82
101
|
const toShow = analysis.suggested_matches.slice(0, maxToShow);
|
|
83
102
|
for (const match of toShow) {
|
|
@@ -89,6 +108,11 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
89
108
|
}
|
|
90
109
|
return lines.join('\n');
|
|
91
110
|
}
|
|
111
|
+
function formatYnabTransactionLine(txn) {
|
|
112
|
+
const amountStr = formatAmount(txn.amount);
|
|
113
|
+
const payee = txn.payee ?? 'Unknown';
|
|
114
|
+
return ` ${txn.date} - ${payee.substring(0, 40).padEnd(40)} ${amountStr}`;
|
|
115
|
+
}
|
|
92
116
|
function formatBankTransactionLine(txn) {
|
|
93
117
|
const amountStr = formatAmount(txn.amount);
|
|
94
118
|
return ` ${txn.date} - ${txn.payee.substring(0, 40).padEnd(40)} ${amountStr}`;
|
|
@@ -32,6 +32,8 @@ export interface ReconciliationSummary {
|
|
|
32
32
|
statement_date_range: string;
|
|
33
33
|
bank_transactions_count: number;
|
|
34
34
|
ynab_transactions_count: number;
|
|
35
|
+
ynab_in_range_count: number;
|
|
36
|
+
ynab_outside_range_count: number;
|
|
35
37
|
auto_matched: number;
|
|
36
38
|
suggested_matches: number;
|
|
37
39
|
unmatched_bank: number;
|
|
@@ -59,6 +61,7 @@ export interface ReconciliationAnalysis {
|
|
|
59
61
|
suggested_matches: TransactionMatch[];
|
|
60
62
|
unmatched_bank: BankTransaction[];
|
|
61
63
|
unmatched_ynab: YNABTransaction[];
|
|
64
|
+
ynab_outside_date_range: YNABTransaction[];
|
|
62
65
|
balance_info: BalanceInfo;
|
|
63
66
|
next_steps: string[];
|
|
64
67
|
insights: ReconciliationInsight[];
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import * as ynab from 'ynab';
|
|
3
|
+
export declare const ListTransactionsSchema: z.ZodObject<{
|
|
4
|
+
budget_id: z.ZodString;
|
|
5
|
+
account_id: z.ZodOptional<z.ZodString>;
|
|
6
|
+
category_id: z.ZodOptional<z.ZodString>;
|
|
7
|
+
since_date: z.ZodOptional<z.ZodString>;
|
|
8
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
9
|
+
uncategorized: "uncategorized";
|
|
10
|
+
unapproved: "unapproved";
|
|
11
|
+
}>>;
|
|
12
|
+
}, z.core.$strict>;
|
|
13
|
+
export type ListTransactionsParams = z.infer<typeof ListTransactionsSchema>;
|
|
14
|
+
export declare const GetTransactionSchema: z.ZodObject<{
|
|
15
|
+
budget_id: z.ZodString;
|
|
16
|
+
transaction_id: z.ZodString;
|
|
17
|
+
}, z.core.$strict>;
|
|
18
|
+
export type GetTransactionParams = z.infer<typeof GetTransactionSchema>;
|
|
19
|
+
export declare const CreateTransactionSchema: z.ZodObject<{
|
|
20
|
+
budget_id: z.ZodString;
|
|
21
|
+
account_id: z.ZodString;
|
|
22
|
+
amount: z.ZodNumber;
|
|
23
|
+
date: z.ZodString;
|
|
24
|
+
payee_name: z.ZodOptional<z.ZodString>;
|
|
25
|
+
payee_id: z.ZodOptional<z.ZodString>;
|
|
26
|
+
category_id: z.ZodOptional<z.ZodString>;
|
|
27
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
28
|
+
cleared: z.ZodOptional<z.ZodEnum<{
|
|
29
|
+
cleared: "cleared";
|
|
30
|
+
uncleared: "uncleared";
|
|
31
|
+
reconciled: "reconciled";
|
|
32
|
+
}>>;
|
|
33
|
+
approved: z.ZodOptional<z.ZodBoolean>;
|
|
34
|
+
flag_color: z.ZodOptional<z.ZodEnum<{
|
|
35
|
+
red: "red";
|
|
36
|
+
orange: "orange";
|
|
37
|
+
yellow: "yellow";
|
|
38
|
+
green: "green";
|
|
39
|
+
blue: "blue";
|
|
40
|
+
purple: "purple";
|
|
41
|
+
}>>;
|
|
42
|
+
import_id: z.ZodOptional<z.ZodString>;
|
|
43
|
+
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
44
|
+
subtransactions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
45
|
+
amount: z.ZodNumber;
|
|
46
|
+
payee_name: z.ZodOptional<z.ZodString>;
|
|
47
|
+
payee_id: z.ZodOptional<z.ZodString>;
|
|
48
|
+
category_id: z.ZodOptional<z.ZodString>;
|
|
49
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
50
|
+
}, z.core.$strict>>>;
|
|
51
|
+
}, z.core.$strict>;
|
|
52
|
+
export type CreateTransactionParams = z.infer<typeof CreateTransactionSchema>;
|
|
53
|
+
export interface SubtransactionInput {
|
|
54
|
+
amount: number;
|
|
55
|
+
payee_name?: string;
|
|
56
|
+
payee_id?: string;
|
|
57
|
+
category_id?: string;
|
|
58
|
+
memo?: string;
|
|
59
|
+
}
|
|
60
|
+
export type BulkTransactionInput = Omit<CreateTransactionParams, 'budget_id' | 'dry_run' | 'subtransactions'>;
|
|
61
|
+
export declare const CreateTransactionsSchema: z.ZodObject<{
|
|
62
|
+
budget_id: z.ZodString;
|
|
63
|
+
transactions: z.ZodArray<z.ZodObject<{
|
|
64
|
+
date: z.ZodString;
|
|
65
|
+
cleared: z.ZodOptional<z.ZodEnum<{
|
|
66
|
+
cleared: "cleared";
|
|
67
|
+
uncleared: "uncleared";
|
|
68
|
+
reconciled: "reconciled";
|
|
69
|
+
}>>;
|
|
70
|
+
amount: z.ZodNumber;
|
|
71
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
72
|
+
approved: z.ZodOptional<z.ZodBoolean>;
|
|
73
|
+
flag_color: z.ZodOptional<z.ZodEnum<{
|
|
74
|
+
red: "red";
|
|
75
|
+
orange: "orange";
|
|
76
|
+
yellow: "yellow";
|
|
77
|
+
green: "green";
|
|
78
|
+
blue: "blue";
|
|
79
|
+
purple: "purple";
|
|
80
|
+
}>>;
|
|
81
|
+
account_id: z.ZodString;
|
|
82
|
+
payee_id: z.ZodOptional<z.ZodString>;
|
|
83
|
+
category_id: z.ZodOptional<z.ZodString>;
|
|
84
|
+
import_id: z.ZodOptional<z.ZodString>;
|
|
85
|
+
payee_name: z.ZodOptional<z.ZodString>;
|
|
86
|
+
}, z.core.$strict>>;
|
|
87
|
+
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
88
|
+
}, z.core.$strict>;
|
|
89
|
+
export type CreateTransactionsParams = z.infer<typeof CreateTransactionsSchema>;
|
|
90
|
+
export interface BulkTransactionResult {
|
|
91
|
+
request_index: number;
|
|
92
|
+
status: 'created' | 'duplicate' | 'failed';
|
|
93
|
+
transaction_id?: string | undefined;
|
|
94
|
+
correlation_key: string;
|
|
95
|
+
error_code?: string | undefined;
|
|
96
|
+
error?: string | undefined;
|
|
97
|
+
}
|
|
98
|
+
export interface BulkCreateResponse {
|
|
99
|
+
success: boolean;
|
|
100
|
+
server_knowledge?: number;
|
|
101
|
+
summary: {
|
|
102
|
+
total_requested: number;
|
|
103
|
+
created: number;
|
|
104
|
+
duplicates: number;
|
|
105
|
+
failed: number;
|
|
106
|
+
};
|
|
107
|
+
results: BulkTransactionResult[];
|
|
108
|
+
transactions?: ynab.TransactionDetail[];
|
|
109
|
+
duplicate_import_ids?: string[];
|
|
110
|
+
message?: string;
|
|
111
|
+
mode?: 'full' | 'summary' | 'ids_only';
|
|
112
|
+
}
|
|
113
|
+
export declare const CreateReceiptSplitTransactionSchema: z.ZodObject<{
|
|
114
|
+
budget_id: z.ZodString;
|
|
115
|
+
account_id: z.ZodString;
|
|
116
|
+
payee_name: z.ZodString;
|
|
117
|
+
date: z.ZodOptional<z.ZodString>;
|
|
118
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
119
|
+
receipt_subtotal: z.ZodOptional<z.ZodNumber>;
|
|
120
|
+
receipt_tax: z.ZodNumber;
|
|
121
|
+
receipt_total: z.ZodNumber;
|
|
122
|
+
categories: z.ZodArray<z.ZodObject<{
|
|
123
|
+
category_id: z.ZodString;
|
|
124
|
+
category_name: z.ZodOptional<z.ZodString>;
|
|
125
|
+
items: z.ZodArray<z.ZodObject<{
|
|
126
|
+
name: z.ZodString;
|
|
127
|
+
amount: z.ZodNumber;
|
|
128
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
129
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
130
|
+
}, z.core.$strict>>;
|
|
131
|
+
}, z.core.$strict>>;
|
|
132
|
+
cleared: z.ZodOptional<z.ZodEnum<{
|
|
133
|
+
cleared: "cleared";
|
|
134
|
+
uncleared: "uncleared";
|
|
135
|
+
reconciled: "reconciled";
|
|
136
|
+
}>>;
|
|
137
|
+
approved: z.ZodOptional<z.ZodBoolean>;
|
|
138
|
+
flag_color: z.ZodOptional<z.ZodEnum<{
|
|
139
|
+
red: "red";
|
|
140
|
+
orange: "orange";
|
|
141
|
+
yellow: "yellow";
|
|
142
|
+
green: "green";
|
|
143
|
+
blue: "blue";
|
|
144
|
+
purple: "purple";
|
|
145
|
+
}>>;
|
|
146
|
+
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
147
|
+
}, z.core.$strict>;
|
|
148
|
+
export type CreateReceiptSplitTransactionParams = z.infer<typeof CreateReceiptSplitTransactionSchema>;
|
|
149
|
+
export interface ReceiptCategoryCalculation {
|
|
150
|
+
category_id: string;
|
|
151
|
+
category_name: string | undefined;
|
|
152
|
+
subtotal_milliunits: number;
|
|
153
|
+
tax_milliunits: number;
|
|
154
|
+
items: {
|
|
155
|
+
name: string;
|
|
156
|
+
amount_milliunits: number;
|
|
157
|
+
quantity: number | undefined;
|
|
158
|
+
memo: string | undefined;
|
|
159
|
+
}[];
|
|
160
|
+
}
|
|
161
|
+
export declare const UpdateTransactionSchema: z.ZodObject<{
|
|
162
|
+
budget_id: z.ZodString;
|
|
163
|
+
transaction_id: z.ZodString;
|
|
164
|
+
account_id: z.ZodOptional<z.ZodString>;
|
|
165
|
+
amount: z.ZodOptional<z.ZodNumber>;
|
|
166
|
+
date: z.ZodOptional<z.ZodString>;
|
|
167
|
+
payee_name: z.ZodOptional<z.ZodString>;
|
|
168
|
+
payee_id: z.ZodOptional<z.ZodString>;
|
|
169
|
+
category_id: z.ZodOptional<z.ZodString>;
|
|
170
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
171
|
+
cleared: z.ZodOptional<z.ZodEnum<{
|
|
172
|
+
cleared: "cleared";
|
|
173
|
+
uncleared: "uncleared";
|
|
174
|
+
reconciled: "reconciled";
|
|
175
|
+
}>>;
|
|
176
|
+
approved: z.ZodOptional<z.ZodBoolean>;
|
|
177
|
+
flag_color: z.ZodOptional<z.ZodEnum<{
|
|
178
|
+
red: "red";
|
|
179
|
+
orange: "orange";
|
|
180
|
+
yellow: "yellow";
|
|
181
|
+
green: "green";
|
|
182
|
+
blue: "blue";
|
|
183
|
+
purple: "purple";
|
|
184
|
+
}>>;
|
|
185
|
+
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
186
|
+
}, z.core.$strict>;
|
|
187
|
+
export type UpdateTransactionParams = z.infer<typeof UpdateTransactionSchema>;
|
|
188
|
+
declare const BulkUpdateTransactionInputSchema: z.ZodObject<{
|
|
189
|
+
id: z.ZodString;
|
|
190
|
+
amount: z.ZodOptional<z.ZodNumber>;
|
|
191
|
+
date: z.ZodOptional<z.ZodString>;
|
|
192
|
+
payee_name: z.ZodOptional<z.ZodString>;
|
|
193
|
+
payee_id: z.ZodOptional<z.ZodString>;
|
|
194
|
+
category_id: z.ZodOptional<z.ZodString>;
|
|
195
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
196
|
+
cleared: z.ZodOptional<z.ZodEnum<{
|
|
197
|
+
cleared: "cleared";
|
|
198
|
+
uncleared: "uncleared";
|
|
199
|
+
reconciled: "reconciled";
|
|
200
|
+
}>>;
|
|
201
|
+
approved: z.ZodOptional<z.ZodBoolean>;
|
|
202
|
+
flag_color: z.ZodOptional<z.ZodEnum<{
|
|
203
|
+
red: "red";
|
|
204
|
+
orange: "orange";
|
|
205
|
+
yellow: "yellow";
|
|
206
|
+
green: "green";
|
|
207
|
+
blue: "blue";
|
|
208
|
+
purple: "purple";
|
|
209
|
+
}>>;
|
|
210
|
+
original_account_id: z.ZodOptional<z.ZodString>;
|
|
211
|
+
original_date: z.ZodOptional<z.ZodString>;
|
|
212
|
+
}, z.core.$strict>;
|
|
213
|
+
export type BulkUpdateTransactionInput = z.infer<typeof BulkUpdateTransactionInputSchema>;
|
|
214
|
+
export declare const UpdateTransactionsSchema: z.ZodObject<{
|
|
215
|
+
budget_id: z.ZodString;
|
|
216
|
+
transactions: z.ZodArray<z.ZodObject<{
|
|
217
|
+
id: z.ZodString;
|
|
218
|
+
amount: z.ZodOptional<z.ZodNumber>;
|
|
219
|
+
date: z.ZodOptional<z.ZodString>;
|
|
220
|
+
payee_name: z.ZodOptional<z.ZodString>;
|
|
221
|
+
payee_id: z.ZodOptional<z.ZodString>;
|
|
222
|
+
category_id: z.ZodOptional<z.ZodString>;
|
|
223
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
224
|
+
cleared: z.ZodOptional<z.ZodEnum<{
|
|
225
|
+
cleared: "cleared";
|
|
226
|
+
uncleared: "uncleared";
|
|
227
|
+
reconciled: "reconciled";
|
|
228
|
+
}>>;
|
|
229
|
+
approved: z.ZodOptional<z.ZodBoolean>;
|
|
230
|
+
flag_color: z.ZodOptional<z.ZodEnum<{
|
|
231
|
+
red: "red";
|
|
232
|
+
orange: "orange";
|
|
233
|
+
yellow: "yellow";
|
|
234
|
+
green: "green";
|
|
235
|
+
blue: "blue";
|
|
236
|
+
purple: "purple";
|
|
237
|
+
}>>;
|
|
238
|
+
original_account_id: z.ZodOptional<z.ZodString>;
|
|
239
|
+
original_date: z.ZodOptional<z.ZodString>;
|
|
240
|
+
}, z.core.$strict>>;
|
|
241
|
+
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
242
|
+
}, z.core.$strict>;
|
|
243
|
+
export type UpdateTransactionsParams = z.infer<typeof UpdateTransactionsSchema>;
|
|
244
|
+
export interface BulkUpdateResult {
|
|
245
|
+
request_index: number;
|
|
246
|
+
status: 'updated' | 'failed';
|
|
247
|
+
transaction_id: string;
|
|
248
|
+
correlation_key: string;
|
|
249
|
+
error_code?: string;
|
|
250
|
+
error?: string;
|
|
251
|
+
}
|
|
252
|
+
export interface BulkUpdateResponse {
|
|
253
|
+
success: boolean;
|
|
254
|
+
server_knowledge?: number;
|
|
255
|
+
summary: {
|
|
256
|
+
total_requested: number;
|
|
257
|
+
updated: number;
|
|
258
|
+
failed: number;
|
|
259
|
+
};
|
|
260
|
+
results: BulkUpdateResult[];
|
|
261
|
+
transactions?: ynab.TransactionDetail[];
|
|
262
|
+
message?: string;
|
|
263
|
+
mode?: 'full' | 'summary' | 'ids_only';
|
|
264
|
+
}
|
|
265
|
+
export declare const DeleteTransactionSchema: z.ZodObject<{
|
|
266
|
+
budget_id: z.ZodString;
|
|
267
|
+
transaction_id: z.ZodString;
|
|
268
|
+
dry_run: z.ZodOptional<z.ZodBoolean>;
|
|
269
|
+
}, z.core.$strict>;
|
|
270
|
+
export type DeleteTransactionParams = z.infer<typeof DeleteTransactionSchema>;
|
|
271
|
+
export interface CorrelationPayload {
|
|
272
|
+
account_id?: string;
|
|
273
|
+
date?: string;
|
|
274
|
+
amount?: number;
|
|
275
|
+
payee_id?: string | null;
|
|
276
|
+
payee_name?: string | null;
|
|
277
|
+
category_id?: string | null;
|
|
278
|
+
memo?: string | null;
|
|
279
|
+
cleared?: ynab.TransactionClearedStatus;
|
|
280
|
+
approved?: boolean;
|
|
281
|
+
flag_color?: ynab.TransactionFlagColor | null;
|
|
282
|
+
import_id?: string | null;
|
|
283
|
+
}
|
|
284
|
+
export interface CorrelationPayloadInput {
|
|
285
|
+
account_id?: string | undefined;
|
|
286
|
+
date?: string | undefined;
|
|
287
|
+
amount?: number | undefined;
|
|
288
|
+
payee_id?: string | null | undefined;
|
|
289
|
+
payee_name?: string | null | undefined;
|
|
290
|
+
category_id?: string | null | undefined;
|
|
291
|
+
memo?: string | null | undefined;
|
|
292
|
+
cleared?: ynab.TransactionClearedStatus | undefined;
|
|
293
|
+
approved?: boolean | undefined;
|
|
294
|
+
flag_color?: ynab.TransactionFlagColor | null | undefined;
|
|
295
|
+
import_id?: string | null | undefined;
|
|
296
|
+
}
|
|
297
|
+
export interface CategorySource {
|
|
298
|
+
category_id?: string | null;
|
|
299
|
+
subtransactions?: {
|
|
300
|
+
category_id?: string | null;
|
|
301
|
+
}[] | null | undefined;
|
|
302
|
+
}
|
|
303
|
+
export interface TransactionCacheInvalidationOptions {
|
|
304
|
+
affectedCategoryIds?: Set<string>;
|
|
305
|
+
invalidateAllCategories?: boolean;
|
|
306
|
+
accountTotalsChanged?: boolean;
|
|
307
|
+
invalidateMonths?: boolean;
|
|
308
|
+
}
|
|
309
|
+
export {};
|