@moatless/bookkeeping 0.1.3 → 0.2.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.
@@ -6,6 +6,7 @@
6
6
  */
7
7
  export interface TraktamenteRate {
8
8
  countryCode: string;
9
+ country: string;
9
10
  year: number;
10
11
  fullDay: number;
11
12
  halfDay: number;
@@ -4,6 +4,203 @@
4
4
  * Rates are updated annually and published by Skatteverket.
5
5
  * Source: https://skatteverket.se/utlandstraktamente
6
6
  */
7
+ /**
8
+ * Country names by country code
9
+ */
10
+ const COUNTRY_NAMES = {
11
+ SE: "Sweden",
12
+ AL: "Albania",
13
+ DZ: "Algeria",
14
+ AS: "American Samoa",
15
+ AO: "Angola",
16
+ AI: "Anguilla",
17
+ AG: "Antigua and Barbuda",
18
+ AR: "Argentina",
19
+ AM: "Armenia",
20
+ AW: "Aruba",
21
+ AU: "Australia",
22
+ AZ: "Azerbaijan",
23
+ BS: "Bahamas",
24
+ BH: "Bahrain",
25
+ BD: "Bangladesh",
26
+ BB: "Barbados",
27
+ BY: "Belarus",
28
+ BE: "Belgium",
29
+ BZ: "Belize",
30
+ BJ: "Benin",
31
+ BM: "Bermuda",
32
+ BO: "Bolivia",
33
+ BQ: "Bonaire",
34
+ BA: "Bosnia and Herzegovina",
35
+ BW: "Botswana",
36
+ BR: "Brazil",
37
+ BN: "Brunei",
38
+ BG: "Bulgaria",
39
+ BF: "Burkina Faso",
40
+ BI: "Burundi",
41
+ KY: "Cayman Islands",
42
+ CF: "Central African Republic",
43
+ CL: "Chile",
44
+ CO: "Colombia",
45
+ CK: "Cook Islands",
46
+ CR: "Costa Rica",
47
+ CW: "Curacao",
48
+ CY: "Cyprus",
49
+ DK: "Denmark",
50
+ DJ: "Djibouti",
51
+ DO: "Dominican Republic",
52
+ EC: "Ecuador",
53
+ EG: "Egypt",
54
+ GQ: "Equatorial Guinea",
55
+ CI: "Ivory Coast",
56
+ SV: "El Salvador",
57
+ ER: "Eritrea",
58
+ EE: "Estonia",
59
+ SZ: "Eswatini",
60
+ ET: "Ethiopia",
61
+ FJ: "Fiji",
62
+ PH: "Philippines",
63
+ FI: "Finland",
64
+ FR: "France",
65
+ GF: "French Guiana",
66
+ PF: "French Polynesia",
67
+ AE: "United Arab Emirates",
68
+ GA: "Gabon",
69
+ GM: "Gambia",
70
+ GE: "Georgia",
71
+ GH: "Ghana",
72
+ GI: "Gibraltar",
73
+ GR: "Greece",
74
+ GD: "Grenada",
75
+ GP: "Guadeloupe",
76
+ GU: "Guam",
77
+ GT: "Guatemala",
78
+ GN: "Guinea",
79
+ GY: "Guyana",
80
+ HT: "Haiti",
81
+ HN: "Honduras",
82
+ HK: "Hong Kong",
83
+ IN: "India",
84
+ ID: "Indonesia",
85
+ IQ: "Iraq",
86
+ IE: "Ireland",
87
+ IS: "Iceland",
88
+ IL: "Israel",
89
+ IT: "Italy",
90
+ JM: "Jamaica",
91
+ JP: "Japan",
92
+ JO: "Jordan",
93
+ KH: "Cambodia",
94
+ CM: "Cameroon",
95
+ CA: "Canada",
96
+ KZ: "Kazakhstan",
97
+ KE: "Kenya",
98
+ CN: "China",
99
+ KG: "Kyrgyzstan",
100
+ KI: "Kiribati",
101
+ CG: "Congo (Brazzaville)",
102
+ CD: "Congo (DRC)",
103
+ XK: "Kosovo",
104
+ HR: "Croatia",
105
+ CU: "Cuba",
106
+ KW: "Kuwait",
107
+ LA: "Laos",
108
+ LS: "Lesotho",
109
+ LV: "Latvia",
110
+ LR: "Liberia",
111
+ LY: "Libya",
112
+ LI: "Liechtenstein",
113
+ LT: "Lithuania",
114
+ LU: "Luxembourg",
115
+ MO: "Macao",
116
+ MG: "Madagascar",
117
+ MW: "Malawi",
118
+ MY: "Malaysia",
119
+ MV: "Maldives",
120
+ ML: "Mali",
121
+ MT: "Malta",
122
+ MA: "Morocco",
123
+ MQ: "Martinique",
124
+ MR: "Mauritania",
125
+ MU: "Mauritius",
126
+ MX: "Mexico",
127
+ FM: "Micronesia",
128
+ MZ: "Mozambique",
129
+ MD: "Moldova",
130
+ MC: "Monaco",
131
+ MN: "Mongolia",
132
+ ME: "Montenegro",
133
+ MM: "Myanmar",
134
+ NA: "Namibia",
135
+ NL: "Netherlands",
136
+ NP: "Nepal",
137
+ NI: "Nicaragua",
138
+ NE: "Niger",
139
+ MK: "North Macedonia",
140
+ NO: "Norway",
141
+ NC: "New Caledonia",
142
+ NZ: "New Zealand",
143
+ OM: "Oman",
144
+ PK: "Pakistan",
145
+ PA: "Panama",
146
+ PG: "Papua New Guinea",
147
+ PY: "Paraguay",
148
+ PE: "Peru",
149
+ PL: "Poland",
150
+ PT: "Portugal",
151
+ PR: "Puerto Rico",
152
+ QA: "Qatar",
153
+ RE: "Reunion",
154
+ RO: "Romania",
155
+ RW: "Rwanda",
156
+ RU: "Russia",
157
+ LC: "Saint Lucia",
158
+ VC: "Saint Vincent and the Grenadines",
159
+ SB: "Solomon Islands",
160
+ WS: "Samoa",
161
+ SA: "Saudi Arabia",
162
+ CH: "Switzerland",
163
+ SN: "Senegal",
164
+ RS: "Serbia",
165
+ SC: "Seychelles",
166
+ SL: "Sierra Leone",
167
+ SG: "Singapore",
168
+ SX: "Sint Maarten",
169
+ SK: "Slovakia",
170
+ SI: "Slovenia",
171
+ ES: "Spain",
172
+ LK: "Sri Lanka",
173
+ GB: "United Kingdom",
174
+ SR: "Suriname",
175
+ ZA: "South Africa",
176
+ KR: "South Korea",
177
+ TJ: "Tajikistan",
178
+ TW: "Taiwan",
179
+ TZ: "Tanzania",
180
+ TD: "Chad",
181
+ TH: "Thailand",
182
+ CZ: "Czech Republic",
183
+ TG: "Togo",
184
+ TO: "Tonga",
185
+ TT: "Trinidad and Tobago",
186
+ TN: "Tunisia",
187
+ TR: "Turkey",
188
+ TM: "Turkmenistan",
189
+ DE: "Germany",
190
+ UG: "Uganda",
191
+ UA: "Ukraine",
192
+ HU: "Hungary",
193
+ UY: "Uruguay",
194
+ US: "United States",
195
+ UZ: "Uzbekistan",
196
+ VU: "Vanuatu",
197
+ VE: "Venezuela",
198
+ VN: "Vietnam",
199
+ ZM: "Zambia",
200
+ AT: "Austria",
201
+ TL: "East Timor",
202
+ XX: "Other countries",
203
+ };
7
204
  /**
8
205
  * Traktamente rates by country code and year (fullDay amount in SEK)
9
206
  * halfDay = Math.floor(fullDay / 2)
@@ -219,6 +416,7 @@ export function getTraktamenteRate(countryCode, year) {
219
416
  const isDomestic = code === "SE";
220
417
  return {
221
418
  countryCode: code,
419
+ country: COUNTRY_NAMES[code] ?? code,
222
420
  year,
223
421
  fullDay,
224
422
  halfDay,
@@ -237,6 +435,7 @@ export function getAllRatesForYear(year) {
237
435
  const isDomestic = code === "SE";
238
436
  rates.push({
239
437
  countryCode: code,
438
+ country: COUNTRY_NAMES[code] ?? code,
240
439
  year,
241
440
  fullDay,
242
441
  halfDay,
@@ -160,7 +160,7 @@ export async function loginFortnox(options) {
160
160
  const tokenResponse = await exchangeCodeForToken(config, callbackResult.code);
161
161
  // Save token
162
162
  const storedToken = saveFortnoxToken(cwd, tokenResponse);
163
- onStatus("Token saved to .kvitton/tokens/fortnox.json");
163
+ onStatus("Token saved to .ledgit/tokens/fortnox.json");
164
164
  return storedToken;
165
165
  }
166
166
  finally {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export * from "./types";
2
- export * from "./sync-types";
3
2
  export * from "./accounting";
4
3
  export { readEntryYaml, readDocumentsYaml, readDocumentYaml, writeEntryYaml, appendLinesToEntry, readAccountsYaml, validateAccountExists, getAccountName, } from "./yaml";
5
4
  export * from "./transformers";
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  // Types (journal entries, documents, fiscal years, etc.)
2
+ // Includes all types from @moatless/bookkeeping-types (sync types, domain types, etc.)
2
3
  export * from "./types";
3
- // Sync types (sync stats, errors, results)
4
- export * from "./sync-types";
5
4
  // Accounting logic
6
5
  export * from "./accounting";
7
6
  // YAML utilities (from yaml module - entry helpers, etc.)
@@ -1,17 +1,5 @@
1
- export interface SyncProgress {
2
- current: number;
3
- total: number;
4
- message?: string;
5
- /** Phase of sync: discovering (listing) or fetching (getting details) */
6
- phase?: "discovering" | "fetching";
7
- }
8
- export interface FiscalYearSummary {
9
- id: number;
10
- year: number;
11
- fromDate: string;
12
- toDate: string;
13
- entryCount: number;
14
- }
1
+ import type { SyncProgress, FiscalYearSummary } from "@moatless/bookkeeping-types";
2
+ export type { SyncProgress, FiscalYearSummary };
15
3
  export declare class SyncProgressBar {
16
4
  private bar;
17
5
  private currentPhase;
@@ -1,61 +1 @@
1
- /**
2
- * Result stats for sync operations
3
- */
4
- export interface SyncStats {
5
- fetched: number;
6
- written: number;
7
- skipped: number;
8
- errors: number;
9
- }
10
- /**
11
- * Stats per fiscal year (more detailed)
12
- */
13
- export interface FiscalYearStats {
14
- year: number;
15
- fetched: number;
16
- created: number;
17
- updated: number;
18
- unchanged: number;
19
- failed: number;
20
- }
21
- /**
22
- * Error entry for tracking issues
23
- */
24
- export interface SyncError {
25
- year: number;
26
- externalId: string;
27
- message: string;
28
- }
29
- /**
30
- * Complete sync result
31
- */
32
- export interface SyncJournalResult {
33
- success: boolean;
34
- fiscalYears: FiscalYearStats[];
35
- totals: {
36
- fetched: number;
37
- created: number;
38
- updated: number;
39
- unchanged: number;
40
- failed: number;
41
- };
42
- errors: SyncError[];
43
- durationMs: number;
44
- }
45
- /**
46
- * Fiscal year info for sync operations
47
- */
48
- export interface FiscalYearInfo {
49
- /** External ID from provider (used for API calls) */
50
- externalId: number;
51
- /** Calendar year (used for file paths) */
52
- year: number;
53
- }
54
- /**
55
- * Fiscal year with dates (from database)
56
- */
57
- export interface FiscalYearWithDates {
58
- name: string | null;
59
- start_date: string;
60
- end_date: string;
61
- }
1
+ export type { SyncStats, FiscalYearStats, SyncError, SyncJournalResult, FiscalYearInfo, FiscalYearWithDates, SyncProgress, } from "@moatless/bookkeeping-types";
@@ -1,10 +1,5 @@
1
+ export * from "@moatless/bookkeeping-types";
1
2
  export type ApiResponse = {
2
3
  message: string;
3
4
  success: true;
4
5
  };
5
- export * from "./journal-entry";
6
- export * from "./document";
7
- export type { Document as InboxDocument } from "./document";
8
- export * from "./fiscal-year";
9
- export * from "./ledger-account";
10
- export * from "./discarded-item";
@@ -1,10 +1,2 @@
1
- // Journal entry types (used across Git YAML, API, and client)
2
- export * from "./journal-entry";
3
- // Document types
4
- export * from "./document";
5
- // Fiscal year
6
- export * from "./fiscal-year";
7
- // Ledger account
8
- export * from "./ledger-account";
9
- // Discarded items
10
- export * from "./discarded-item";
1
+ // Re-export all types from @moatless/bookkeeping-types
2
+ export * from "@moatless/bookkeeping-types";
package/dist/utils/git.js CHANGED
@@ -5,8 +5,9 @@ const DEFAULT_GITIGNORE = `# Environment files with secrets
5
5
  .env
6
6
  .env.*
7
7
 
8
- # CLI cache
9
- .kvitton/
8
+ # Tokens and cache (sensitive data)
9
+ .ledgit/tokens/
10
+ .ledgit/cache/
10
11
 
11
12
  # OS files
12
13
  .DS_Store
@@ -3,4 +3,4 @@ export { parseYaml, toYaml } from "./yaml";
3
3
  export { withRetry, isRateLimitError, type RetryOptions } from "./retry";
4
4
  export { initGitRepo, commitAll } from "./git";
5
5
  export { getAgentsTemplate, renderAgentsTemplate, type RenderAgentsTemplateOptions, } from "./templates";
6
- export { KVITTON_DIR, getKvittonDir, getTokensDir, getCacheDir, } from "./paths";
6
+ export { LEDGIT_DIR, getLedgitDir, getTokensDir, getCacheDir, } from "./paths";
@@ -3,4 +3,4 @@ export { parseYaml, toYaml } from "./yaml";
3
3
  export { withRetry, isRateLimitError } from "./retry";
4
4
  export { initGitRepo, commitAll } from "./git";
5
5
  export { getAgentsTemplate, renderAgentsTemplate, } from "./templates";
6
- export { KVITTON_DIR, getKvittonDir, getTokensDir, getCacheDir, } from "./paths";
6
+ export { LEDGIT_DIR, getLedgitDir, getTokensDir, getCacheDir, } from "./paths";
@@ -2,11 +2,11 @@
2
2
  * The hidden directory used for internal storage (tokens, cache, etc.)
3
3
  * inside the accounting repository.
4
4
  */
5
- export declare const KVITTON_DIR = ".kvitton";
5
+ export declare const LEDGIT_DIR = ".ledgit";
6
6
  /**
7
- * Get the base .kvitton directory path for a given working directory.
7
+ * Get the base .ledgit directory path for a given working directory.
8
8
  */
9
- export declare function getKvittonDir(cwd: string): string;
9
+ export declare function getLedgitDir(cwd: string): string;
10
10
  /**
11
11
  * Get the tokens directory path for storing OAuth tokens.
12
12
  */
@@ -3,22 +3,22 @@ import * as path from "node:path";
3
3
  * The hidden directory used for internal storage (tokens, cache, etc.)
4
4
  * inside the accounting repository.
5
5
  */
6
- export const KVITTON_DIR = ".kvitton";
6
+ export const LEDGIT_DIR = ".ledgit";
7
7
  /**
8
- * Get the base .kvitton directory path for a given working directory.
8
+ * Get the base .ledgit directory path for a given working directory.
9
9
  */
10
- export function getKvittonDir(cwd) {
11
- return path.join(cwd, KVITTON_DIR);
10
+ export function getLedgitDir(cwd) {
11
+ return path.join(cwd, LEDGIT_DIR);
12
12
  }
13
13
  /**
14
14
  * Get the tokens directory path for storing OAuth tokens.
15
15
  */
16
16
  export function getTokensDir(cwd) {
17
- return path.join(cwd, KVITTON_DIR, "tokens");
17
+ return path.join(cwd, LEDGIT_DIR, "tokens");
18
18
  }
19
19
  /**
20
20
  * Get the cache directory path for storing cached data (e.g., currency rates).
21
21
  */
22
22
  export function getCacheDir(cwd) {
23
- return path.join(cwd, KVITTON_DIR, "cache");
23
+ return path.join(cwd, LEDGIT_DIR, "cache");
24
24
  }
@@ -72,21 +72,29 @@ When you run \`create-entry\` on main branch, a new git branch is automatically
72
72
 
73
73
  ## Bookkeeping New Entries
74
74
 
75
- **Important:** Always ask the user for clarification if anything is unclear about the transaction before creating an entry.
76
-
77
75
  To create a journal entry from an inbox document:
78
76
 
79
- 1. **Read the document** - Use \`npx ledgit-cli parse-pdf\` for PDFs to understand the content
80
- 2. **Update documents.yaml** - After parsing, populate missing metadata in \`documents.yaml\`:
77
+ 1. **Read the document** - You can read PDFs directly, or use \`npx ledgit-cli parse-pdf\` to extract text
78
+ 2. **Update documents.yaml** - Populate missing metadata in \`documents.yaml\`:
81
79
  - \`documentDate\`: Invoice/receipt date (YYYY-MM-DD)
82
80
  - \`description\`: Vendor or document name
83
81
  - \`totalAmount\`: With \`amount\` (string) and \`currency\` (e.g., EUR, SEK)
84
82
  3. **Look for similar entries** - Search \`journal-entries/\` for entries from the same vendor or similar transaction types to learn which accounts and tax codes were used previously
85
83
  4. **Check accounts** - Review \`accounts.yaml\` for appropriate expense/revenue accounts
86
- 5. **Determine tax code** - Based on vendor location and transaction type (see Tax Codes below). Explain your reasoning and describe the tax code meaning to the user
87
- 6. **Ask for confirmation** - Before creating, confirm with the user: vendor, amount, accounts (with names), and tax code (with description)
88
- 7. **Create entry** - Run \`npx ledgit-cli create-entry\` with the appropriate parameters
89
- 8. **Review and sync** - The entry is created in \`journal-entries/\`. Review with \`git diff\`, commit, and run \`npx ledgit-cli sync-journal\` to post to {{PROVIDER}}
84
+ 5. **Determine tax code** - Based on vendor location and transaction type (see Tax Codes below)
85
+ 6. **Create entry** - Run \`npx ledgit-cli create-entry\` with the appropriate parameters
86
+ 7. **Review and sync** - The entry is created in \`journal-entries/\`. Review with \`git diff\`, commit, and run \`npx ledgit-cli sync-journal\` to post to {{PROVIDER}}
87
+
88
+ ### GitHub Actions / CI Mode
89
+
90
+ When running in GitHub Actions (automated bookkeeping):
91
+ - **Always proceed** with creating entries using your best judgment
92
+ - **Always end** by creating or updating a PR
93
+ - If anything is unclear, include your questions in the PR description
94
+ - The user will respond via PR comments, which triggers another workflow run
95
+ - Group related entries (same vendor, same week) in one PR when sensible
96
+
97
+ **Never stop and wait for confirmation in CI mode** - the user can't respond until you create a PR.
90
98
 
91
99
  To discard unwanted inbox items:
92
100
  \`\`\`bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moatless/bookkeeping",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,6 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@moatless/api-client": "^0.1.2",
26
+ "@moatless/bookkeeping-types": "workspace:*",
26
27
  "@moatless/fortnox-client": "^0.1.2",
27
28
  "@moatless/bokio-client": "^0.1.2",
28
29
  "cli-progress": "^3.12.0",