Skip to content

Commit 0bb8e3d

Browse files
author
Amram Englander
committed
Fix all write commands and budget month offset (v0.4.1)
1 parent 876a17d commit 0bb8e3d

8 files changed

Lines changed: 75 additions & 19 deletions

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ Commands that accept a `[month]` argument support:
178178
|--------|---------|-------------|
179179
| `current` | `riseup spending current` | Current budget month (default) |
180180
| `prev` | `riseup spending prev` | Previous month |
181-
| `-N` | `riseup spending -2` | N months back |
182181
| `YYYY-MM` | `riseup spending 2026-01` | Specific month |
183182

184183
## AI Agent Skills

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "riseup-cli",
3-
"version": "0.4.0",
3+
"version": "0.4.1",
44
"description": "Unofficial CLI for RiseUp personal finance, query your spending, income and balances from the terminal",
55
"type": "module",
66
"bin": {

src/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const program = new Command();
2727
program
2828
.name("riseup")
2929
.description("Unofficial RiseUp Finance CLI")
30-
.version("0.4.0");
30+
.version("0.4.1");
3131

3232
// Global options
3333
program.option("--json", "Output as JSON");

src/client/RiseUpClient.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,26 +95,26 @@ export class RiseUpClient {
9595

9696
/** Transaction write operations. */
9797
transactions = {
98-
classify: (transactionId: string, expense: string, applyTo: "single" | "all" = "all") =>
99-
this.http.post("/api/enrichment-update/save-enrichment", { transactionId, expense, applyTo }),
98+
classify: (transactionId: string, businessName: string, expense: string, applyTo: "single" | "all" = "all") =>
99+
this.http.postText("/api/enrichment-update/save-enrichment", { transactionId, businessName, expense, applyTo }),
100100

101-
rename: (transactionId: string, displayName: string, applyTo: "single" | "all" = "single") =>
102-
this.http.post("/api/enrichment-update/save-enrichment", { transactionId, displayName, applyTo }),
101+
rename: (transactionId: string, businessName: string, expense: string, applyTo: "single" | "all" = "single") =>
102+
this.http.postText("/api/enrichment-update/save-enrichment", { transactionId, businessName, expense, applyTo }),
103103

104104
comment: (transactionId: string, comment: string) =>
105-
this.http.post("/api/enrichment-update/save-comments", { transactionId, comment }),
105+
this.http.postText("/api/enrichment-update/save-comments", { transactionId, comment }),
106106

107107
exclude: (transactionId: string) =>
108-
this.http.post("/api/investigator/answers/budget-category", { transactionId, budgetCategory: "excluded" }),
108+
this.http.postText("/api/investigator/answers/budget-category", { transactionId, budgetCategory: "excluded" }),
109109

110110
include: (transactionId: string) =>
111-
this.http.post("/api/investigator/answers/unexclude-transaction", { transactionId }),
111+
this.http.postText("/api/investigator/answers/unexclude-transaction", { transactionId }),
112112

113113
setBudgetType: (transactionId: string, budgetCategory: "fixed" | "variable") =>
114-
this.http.post("/api/investigator/answers/budget-category", { transactionId, budgetCategory }),
114+
this.http.postText("/api/investigator/answers/budget-category", { transactionId, budgetCategory }),
115115

116116
merge: (transactionId: string, input: string = "approved") =>
117-
this.http.post("/api/investigator/answers/merge", { papasMergeInput: [{ transactionId, input }] }),
117+
this.http.postText("/api/investigator/answers/merge", { papasMergeInput: [{ transactionId, input }] }),
118118

119119
adjustPrediction: (payload: {
120120
envelopeId: string;
@@ -124,7 +124,7 @@ export class RiseUpClient {
124124
isPermanent?: boolean;
125125
monthsAhead?: number;
126126
}) =>
127-
this.http.post("/api/prediction-update/update-amount", {
127+
this.http.postText("/api/prediction-update/update-amount", {
128128
...payload,
129129
isPermanent: payload.isPermanent ?? true,
130130
monthsAhead: payload.monthsAhead ?? 1,
@@ -147,11 +147,19 @@ export class RiseUpClient {
147147

148148
/**
149149
* Fetch budgets starting from a given date.
150+
*
151+
* The RiseUp API has a +1 month offset: requesting "2026-03" returns
152+
* budgetDate "2026-02". We compensate here so callers get the month
153+
* they actually asked for.
154+
*
150155
* @param date e.g. "2026-03"
151156
* @param count number of months to fetch (default 1)
152157
*/
153158
async getBudgets(date: string, count = 1): Promise<Budget[]> {
154-
return this.http.getJson<Budget[]>(`/api/budget/${date}/${count}`);
159+
const [year, month] = date.split("-").map(Number);
160+
const adjusted = new Date(year, month, 1); // month is already 1-based, so this adds +1
161+
const apiDate = `${adjusted.getFullYear()}-${String(adjusted.getMonth() + 1).padStart(2, "0")}`;
162+
return this.http.getJson<Budget[]>(`/api/budget/${apiDate}/${count}`);
155163
}
156164

157165
/** Get the oldest budget date the user has (e.g. "2025-06"). */

src/client/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export interface Transaction {
5555
sequencerName?: string;
5656
modelScore?: number;
5757
aiEnrichment?: AiEnrichment;
58+
customerComment?: string;
5859
accountNumberPiiValue?: string;
5960
}
6061

@@ -439,7 +440,7 @@ export interface StoredSession {
439440
export interface SaveEnrichmentPayload {
440441
transactionId: string;
441442
expense?: string;
442-
displayName?: string;
443+
businessName?: string;
443444
applyTo?: "single" | "all";
444445
}
445446

src/commands/manage.ts

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,33 @@
11
import chalk from "chalk";
22
import type { Command } from "commander";
33
import type { Transaction } from "../client/types.js";
4+
import type { RiseUpClient } from "../client/RiseUpClient.js";
45
import { parseMonth } from "../utils/dates.js";
56
import { formatNIS } from "../formatters/currency.js";
67
import { createTable, printTable } from "../formatters/table.js";
78
import { printJson } from "../formatters/json.js";
89
import { withClient } from "./helpers.js";
910
import { fetchBudgetTransactions } from "./budget-helpers.js";
1011

12+
/**
13+
* Search current and previous month budgets for a transaction by ID.
14+
* Returns the Transaction if found, or null.
15+
*/
16+
async function findTransaction(
17+
client: RiseUpClient,
18+
transactionId: string,
19+
): Promise<Transaction | null> {
20+
// Try current month first, then previous
21+
for (const month of ["current", "prev"] as const) {
22+
const date = parseMonth(month === "current" ? undefined : "prev");
23+
const result = await fetchBudgetTransactions(client, date);
24+
if (!result) continue;
25+
const tx = result.transactions.find((t) => t.transactionId === transactionId);
26+
if (tx) return tx;
27+
}
28+
return null;
29+
}
30+
1131
// ── classify ────────────────────────────────
1232

1333
export async function classifyAction(
@@ -21,7 +41,20 @@ export async function classifyAction(
2141
const applyTo = (opts.applyTo as "single" | "all") ?? "all";
2242

2343
await withClient(async (client) => {
24-
await client.transactions.classify(transactionId, category, applyTo);
44+
// The save-enrichment API requires the businessName field.
45+
const tx = await findTransaction(client, transactionId);
46+
if (!tx) {
47+
const msg = `Transaction ${transactionId} not found in current or previous month budgets.`;
48+
if (json) {
49+
printJson({ error: msg });
50+
} else {
51+
console.error(chalk.red(msg));
52+
}
53+
process.exitCode = 1;
54+
return;
55+
}
56+
57+
await client.transactions.classify(transactionId, tx.businessName, category, applyTo);
2558
if (json) {
2659
printJson({ success: true, transactionId, category, applyTo });
2760
} else {
@@ -43,9 +76,23 @@ export async function renameAction(
4376
const applyTo = (opts.applyTo as "single" | "all") ?? "single";
4477

4578
await withClient(async (client) => {
46-
await client.transactions.rename(transactionId, name, applyTo);
79+
// The save-enrichment API requires the expense (category) field.
80+
// Look up the transaction to get its current category.
81+
const tx = await findTransaction(client, transactionId);
82+
if (!tx) {
83+
const msg = `Transaction ${transactionId} not found in current or previous month budgets.`;
84+
if (json) {
85+
printJson({ error: msg });
86+
} else {
87+
console.error(chalk.red(msg));
88+
}
89+
process.exitCode = 1;
90+
return;
91+
}
92+
93+
await client.transactions.rename(transactionId, name, tx.expense, applyTo);
4794
if (json) {
48-
printJson({ success: true, transactionId, displayName: name, applyTo });
95+
printJson({ success: true, transactionId, businessName: name, expense: tx.expense, applyTo });
4996
} else {
5097
console.log(chalk.green(`Transaction ${transactionId} renamed to "${name}" (apply: ${applyTo})`));
5198
}

src/commands/transactions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,14 @@ export async function transactionsAction(
8282
if (json) {
8383
printJson(
8484
transactions.map((tx) => ({
85+
transactionId: tx.transactionId,
8586
date: tx.transactionDate,
8687
amount: getDisplayAmount(tx),
8788
businessName: tx.businessName,
8889
category: tx.expense,
8990
source: tx.source,
9091
isIncome: tx.isIncome,
92+
...(tx.customerComment ? { comment: tx.customerComment } : {}),
9193
})),
9294
);
9395
return;

src/data/SKILL.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ Always use `--json` when you need to do custom analysis (e.g., finding subscript
114114
Commands accepting a month argument support:
115115
- `current` — current budget month (default)
116116
- `prev` — previous month
117-
- `-1`, `-2`, `-3` — relative months back
118117
- `2026-02` — specific year-month
119118

120119
Data is available for approximately 10 months back.

0 commit comments

Comments
 (0)