@robosystems/client 0.2.49 → 0.3.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 (190) hide show
  1. package/extensions/InvestorClient.d.ts +91 -0
  2. package/extensions/InvestorClient.js +223 -0
  3. package/extensions/InvestorClient.ts +501 -0
  4. package/extensions/LedgerClient.d.ts +183 -309
  5. package/extensions/LedgerClient.js +268 -587
  6. package/extensions/LedgerClient.ts +777 -903
  7. package/extensions/ReportClient.d.ts +77 -115
  8. package/extensions/ReportClient.js +124 -211
  9. package/extensions/ReportClient.ts +298 -358
  10. package/extensions/config.js +1 -1
  11. package/extensions/config.ts +1 -1
  12. package/extensions/graphql/client.d.ts +46 -0
  13. package/extensions/graphql/client.js +75 -0
  14. package/extensions/graphql/client.ts +82 -0
  15. package/extensions/graphql/generated/graphql.d.ts +1786 -0
  16. package/extensions/graphql/generated/graphql.js +2671 -0
  17. package/extensions/graphql/generated/graphql.ts +4491 -0
  18. package/extensions/graphql/queries/investor/holdings.d.ts +8 -0
  19. package/extensions/graphql/queries/investor/holdings.js +36 -0
  20. package/extensions/graphql/queries/investor/holdings.ts +34 -0
  21. package/extensions/graphql/queries/investor/portfolio.d.ts +4 -0
  22. package/extensions/graphql/queries/investor/portfolio.js +21 -0
  23. package/extensions/graphql/queries/investor/portfolio.ts +19 -0
  24. package/extensions/graphql/queries/investor/portfolios.d.ts +4 -0
  25. package/extensions/graphql/queries/investor/portfolios.js +29 -0
  26. package/extensions/graphql/queries/investor/portfolios.ts +27 -0
  27. package/extensions/graphql/queries/investor/position.d.ts +4 -0
  28. package/extensions/graphql/queries/investor/position.js +33 -0
  29. package/extensions/graphql/queries/investor/position.ts +31 -0
  30. package/extensions/graphql/queries/investor/positions.d.ts +8 -0
  31. package/extensions/graphql/queries/investor/positions.js +57 -0
  32. package/extensions/graphql/queries/investor/positions.ts +55 -0
  33. package/extensions/graphql/queries/investor/securities.d.ts +8 -0
  34. package/extensions/graphql/queries/investor/securities.js +50 -0
  35. package/extensions/graphql/queries/investor/securities.ts +48 -0
  36. package/extensions/graphql/queries/investor/security.d.ts +4 -0
  37. package/extensions/graphql/queries/investor/security.js +26 -0
  38. package/extensions/graphql/queries/investor/security.ts +24 -0
  39. package/extensions/graphql/queries/ledger/accountRollups.d.ts +7 -0
  40. package/extensions/graphql/queries/ledger/accountRollups.js +36 -0
  41. package/extensions/graphql/queries/ledger/accountRollups.ts +34 -0
  42. package/extensions/graphql/queries/ledger/accountTree.d.ts +11 -0
  43. package/extensions/graphql/queries/ledger/accountTree.js +61 -0
  44. package/extensions/graphql/queries/ledger/accountTree.ts +59 -0
  45. package/extensions/graphql/queries/ledger/accounts.d.ts +8 -0
  46. package/extensions/graphql/queries/ledger/accounts.js +45 -0
  47. package/extensions/graphql/queries/ledger/accounts.ts +43 -0
  48. package/extensions/graphql/queries/ledger/closingBookStructures.d.ts +6 -0
  49. package/extensions/graphql/queries/ledger/closingBookStructures.js +27 -0
  50. package/extensions/graphql/queries/ledger/closingBookStructures.ts +25 -0
  51. package/extensions/graphql/queries/ledger/elements.d.ts +6 -0
  52. package/extensions/graphql/queries/ledger/elements.js +56 -0
  53. package/extensions/graphql/queries/ledger/elements.ts +54 -0
  54. package/extensions/graphql/queries/ledger/entities.d.ts +7 -0
  55. package/extensions/graphql/queries/ledger/entities.js +31 -0
  56. package/extensions/graphql/queries/ledger/entities.ts +29 -0
  57. package/extensions/graphql/queries/ledger/entity.d.ts +14 -0
  58. package/extensions/graphql/queries/ledger/entity.js +55 -0
  59. package/extensions/graphql/queries/ledger/entity.ts +54 -0
  60. package/extensions/graphql/queries/ledger/fiscalCalendar.d.ts +8 -0
  61. package/extensions/graphql/queries/ledger/fiscalCalendar.js +35 -0
  62. package/extensions/graphql/queries/ledger/fiscalCalendar.ts +33 -0
  63. package/extensions/graphql/queries/ledger/mappedTrialBalance.d.ts +9 -0
  64. package/extensions/graphql/queries/ledger/mappedTrialBalance.js +29 -0
  65. package/extensions/graphql/queries/ledger/mappedTrialBalance.ts +27 -0
  66. package/extensions/graphql/queries/ledger/mapping.d.ts +5 -0
  67. package/extensions/graphql/queries/ledger/mapping.js +35 -0
  68. package/extensions/graphql/queries/ledger/mapping.ts +33 -0
  69. package/extensions/graphql/queries/ledger/mappingCoverage.d.ts +5 -0
  70. package/extensions/graphql/queries/ledger/mappingCoverage.js +22 -0
  71. package/extensions/graphql/queries/ledger/mappingCoverage.ts +20 -0
  72. package/extensions/graphql/queries/ledger/mappings.d.ts +6 -0
  73. package/extensions/graphql/queries/ledger/mappings.js +23 -0
  74. package/extensions/graphql/queries/ledger/mappings.ts +21 -0
  75. package/extensions/graphql/queries/ledger/periodCloseStatus.d.ts +6 -0
  76. package/extensions/graphql/queries/ledger/periodCloseStatus.js +29 -0
  77. package/extensions/graphql/queries/ledger/periodCloseStatus.ts +27 -0
  78. package/extensions/graphql/queries/ledger/periodDrafts.d.ts +8 -0
  79. package/extensions/graphql/queries/ledger/periodDrafts.js +45 -0
  80. package/extensions/graphql/queries/ledger/periodDrafts.ts +43 -0
  81. package/extensions/graphql/queries/ledger/publishList.d.ts +5 -0
  82. package/extensions/graphql/queries/ledger/publishList.js +29 -0
  83. package/extensions/graphql/queries/ledger/publishList.ts +27 -0
  84. package/extensions/graphql/queries/ledger/publishLists.d.ts +5 -0
  85. package/extensions/graphql/queries/ledger/publishLists.js +29 -0
  86. package/extensions/graphql/queries/ledger/publishLists.ts +27 -0
  87. package/extensions/graphql/queries/ledger/report.d.ts +5 -0
  88. package/extensions/graphql/queries/ledger/report.js +40 -0
  89. package/extensions/graphql/queries/ledger/report.ts +38 -0
  90. package/extensions/graphql/queries/ledger/reportingTaxonomy.d.ts +6 -0
  91. package/extensions/graphql/queries/ledger/reportingTaxonomy.js +27 -0
  92. package/extensions/graphql/queries/ledger/reportingTaxonomy.ts +25 -0
  93. package/extensions/graphql/queries/ledger/reports.d.ts +8 -0
  94. package/extensions/graphql/queries/ledger/reports.js +45 -0
  95. package/extensions/graphql/queries/ledger/reports.ts +43 -0
  96. package/extensions/graphql/queries/ledger/scheduleFacts.d.ts +7 -0
  97. package/extensions/graphql/queries/ledger/scheduleFacts.js +24 -0
  98. package/extensions/graphql/queries/ledger/scheduleFacts.ts +22 -0
  99. package/extensions/graphql/queries/ledger/schedules.d.ts +6 -0
  100. package/extensions/graphql/queries/ledger/schedules.js +24 -0
  101. package/extensions/graphql/queries/ledger/schedules.ts +22 -0
  102. package/extensions/graphql/queries/ledger/statement.d.ts +9 -0
  103. package/extensions/graphql/queries/ledger/statement.js +43 -0
  104. package/extensions/graphql/queries/ledger/statement.ts +41 -0
  105. package/extensions/graphql/queries/ledger/structures.d.ts +5 -0
  106. package/extensions/graphql/queries/ledger/structures.js +22 -0
  107. package/extensions/graphql/queries/ledger/structures.ts +20 -0
  108. package/extensions/graphql/queries/ledger/summary.d.ts +7 -0
  109. package/extensions/graphql/queries/ledger/summary.js +25 -0
  110. package/extensions/graphql/queries/ledger/summary.ts +23 -0
  111. package/extensions/graphql/queries/ledger/taxonomies.d.ts +5 -0
  112. package/extensions/graphql/queries/ledger/taxonomies.js +28 -0
  113. package/extensions/graphql/queries/ledger/taxonomies.ts +26 -0
  114. package/extensions/graphql/queries/ledger/transaction.d.ts +6 -0
  115. package/extensions/graphql/queries/ledger/transaction.js +49 -0
  116. package/extensions/graphql/queries/ledger/transaction.ts +47 -0
  117. package/extensions/graphql/queries/ledger/transactions.d.ts +7 -0
  118. package/extensions/graphql/queries/ledger/transactions.js +49 -0
  119. package/extensions/graphql/queries/ledger/transactions.ts +47 -0
  120. package/extensions/graphql/queries/ledger/trialBalance.d.ts +7 -0
  121. package/extensions/graphql/queries/ledger/trialBalance.js +28 -0
  122. package/extensions/graphql/queries/ledger/trialBalance.ts +26 -0
  123. package/extensions/graphql/queries/ledger/unmappedElements.d.ts +8 -0
  124. package/extensions/graphql/queries/ledger/unmappedElements.js +29 -0
  125. package/extensions/graphql/queries/ledger/unmappedElements.ts +27 -0
  126. package/extensions/hooks.d.ts +1 -1
  127. package/extensions/index.d.ts +5 -1
  128. package/extensions/index.js +13 -1
  129. package/extensions/index.ts +14 -0
  130. package/index.ts +2 -2
  131. package/package.json +14 -5
  132. package/sdk/index.d.ts +2 -2
  133. package/sdk/index.js +38 -73
  134. package/sdk/index.ts +2 -2
  135. package/sdk/sdk.gen.d.ts +100 -325
  136. package/sdk/sdk.gen.js +228 -592
  137. package/sdk/sdk.gen.ts +193 -556
  138. package/sdk/types.gen.d.ts +4522 -7708
  139. package/sdk/types.gen.ts +4569 -7983
  140. package/sdk.gen.d.ts +100 -325
  141. package/sdk.gen.js +228 -592
  142. package/sdk.gen.ts +193 -556
  143. package/types.gen.d.ts +4522 -7708
  144. package/types.gen.ts +4569 -7983
  145. package/extensions/AgentClient.test.ts +0 -403
  146. package/extensions/LedgerClient.test.ts +0 -1655
  147. package/extensions/OperationClient.test.ts +0 -365
  148. package/extensions/QueryClient.test.ts +0 -432
  149. package/extensions/ReportClient.test.ts +0 -828
  150. package/extensions/SSEClient.test.ts +0 -375
  151. package/extensions/config.test.ts +0 -199
  152. package/extensions/hooks.test.ts +0 -373
  153. package/extensions/index.test.ts +0 -420
  154. package/sdk-extensions/AgentClient.d.ts +0 -82
  155. package/sdk-extensions/AgentClient.js +0 -218
  156. package/sdk-extensions/AgentClient.test.ts +0 -403
  157. package/sdk-extensions/AgentClient.ts +0 -321
  158. package/sdk-extensions/LedgerClient.d.ts +0 -416
  159. package/sdk-extensions/LedgerClient.js +0 -737
  160. package/sdk-extensions/LedgerClient.test.ts +0 -1655
  161. package/sdk-extensions/LedgerClient.ts +0 -1249
  162. package/sdk-extensions/OperationClient.d.ts +0 -65
  163. package/sdk-extensions/OperationClient.js +0 -251
  164. package/sdk-extensions/OperationClient.test.ts +0 -365
  165. package/sdk-extensions/OperationClient.ts +0 -324
  166. package/sdk-extensions/QueryClient.d.ts +0 -52
  167. package/sdk-extensions/QueryClient.js +0 -313
  168. package/sdk-extensions/QueryClient.test.ts +0 -432
  169. package/sdk-extensions/QueryClient.ts +0 -420
  170. package/sdk-extensions/README.md +0 -901
  171. package/sdk-extensions/ReportClient.d.ts +0 -151
  172. package/sdk-extensions/ReportClient.js +0 -278
  173. package/sdk-extensions/ReportClient.test.ts +0 -828
  174. package/sdk-extensions/ReportClient.ts +0 -486
  175. package/sdk-extensions/SSEClient.d.ts +0 -62
  176. package/sdk-extensions/SSEClient.js +0 -154
  177. package/sdk-extensions/SSEClient.test.ts +0 -375
  178. package/sdk-extensions/SSEClient.ts +0 -210
  179. package/sdk-extensions/config.d.ts +0 -57
  180. package/sdk-extensions/config.js +0 -152
  181. package/sdk-extensions/config.test.ts +0 -199
  182. package/sdk-extensions/config.ts +0 -175
  183. package/sdk-extensions/hooks.d.ts +0 -110
  184. package/sdk-extensions/hooks.js +0 -384
  185. package/sdk-extensions/hooks.test.ts +0 -373
  186. package/sdk-extensions/hooks.ts +0 -459
  187. package/sdk-extensions/index.d.ts +0 -63
  188. package/sdk-extensions/index.js +0 -164
  189. package/sdk-extensions/index.test.ts +0 -420
  190. package/sdk-extensions/index.ts +0 -203
@@ -1,1249 +0,0 @@
1
- 'use client'
2
-
3
- /**
4
- * Ledger Client for RoboSystems API
5
- *
6
- * High-level client for all ledger concerns: chart of accounts, transactions,
7
- * trial balance, taxonomy, mappings, and AI auto-mapping. This is the
8
- * operational backbone — reports consume these as inputs.
9
- */
10
-
11
- import {
12
- autoMapElements,
13
- closeFiscalPeriod,
14
- createClosingEntry,
15
- createManualClosingEntry,
16
- createMappingAssociation,
17
- createSchedule,
18
- createStructure,
19
- deleteMappingAssociation,
20
- getAccountRollups,
21
- getClosingBookStructures,
22
- getFiscalCalendar,
23
- getLedgerAccountTree,
24
- getLedgerEntity,
25
- getLedgerSummary,
26
- getLedgerTransaction,
27
- getLedgerTrialBalance,
28
- getMappedTrialBalance,
29
- getMappingCoverage,
30
- getMappingDetail,
31
- getPeriodCloseStatus,
32
- getReportingTaxonomy,
33
- getScheduleFacts,
34
- initializeLedger,
35
- listElements,
36
- listLedgerAccounts,
37
- listLedgerTransactions,
38
- listMappings,
39
- listPeriodDrafts,
40
- listSchedules,
41
- listStructures,
42
- reopenFiscalPeriod,
43
- setCloseTarget,
44
- truncateSchedule,
45
- } from '../sdk/sdk.gen'
46
- import type {
47
- AccountListResponse,
48
- AccountRollupsResponse,
49
- AccountTreeResponse,
50
- ClosePeriodRequest,
51
- ClosePeriodResponse,
52
- ClosingBookStructuresResponse,
53
- ClosingEntryResponse,
54
- CreateClosingEntryRequest,
55
- CreateManualClosingEntryRequest,
56
- CreateScheduleRequest,
57
- FiscalCalendarResponse,
58
- InitializeLedgerRequest,
59
- InitializeLedgerResponse,
60
- LedgerSummaryResponse,
61
- LedgerTransactionDetailResponse,
62
- LedgerTransactionListResponse,
63
- MappingCoverageResponse,
64
- MappingDetailResponse,
65
- PeriodCloseItemResponse,
66
- PeriodCloseStatusResponse,
67
- PeriodDraftsResponse,
68
- ReopenPeriodRequest,
69
- ScheduleCreatedResponse,
70
- ScheduleFactResponse,
71
- ScheduleFactsResponse,
72
- ScheduleListResponse,
73
- ScheduleSummaryResponse,
74
- SetCloseTargetRequest,
75
- TrialBalanceResponse,
76
- TruncateScheduleRequest,
77
- TruncateScheduleResponse,
78
- } from '../sdk/types.gen'
79
-
80
- // ── Friendly types ──────────────────────────────────────────────────────
81
-
82
- export interface LedgerEntity {
83
- id: string
84
- name: string
85
- legalName: string | null
86
- entityType: string | null
87
- industry: string | null
88
- status: string | null
89
- }
90
-
91
- export interface MappingInfo {
92
- id: string
93
- name: string
94
- description: string | null
95
- structureType: string
96
- taxonomyId: string
97
- isActive: boolean
98
- }
99
-
100
- export interface MappingCoverage {
101
- totalCoaElements: number
102
- mappedCount: number
103
- unmappedCount: number
104
- coveragePercent: number
105
- highConfidence: number
106
- mediumConfidence: number
107
- lowConfidence: number
108
- }
109
-
110
- export interface Structure {
111
- id: string
112
- name: string
113
- structureType: string
114
- }
115
-
116
- export interface Schedule {
117
- structureId: string
118
- name: string
119
- taxonomyName: string
120
- entryTemplate: Record<string, unknown> | null
121
- scheduleMetadata: Record<string, unknown> | null
122
- totalPeriods: number
123
- periodsWithEntries: number
124
- }
125
-
126
- export interface ScheduleCreated {
127
- structureId: string
128
- name: string
129
- taxonomyId: string
130
- totalPeriods: number
131
- totalFacts: number
132
- }
133
-
134
- export interface ScheduleFact {
135
- elementId: string
136
- elementName: string
137
- value: number
138
- periodStart: string
139
- periodEnd: string
140
- }
141
-
142
- export interface PeriodCloseItem {
143
- structureId: string
144
- structureName: string
145
- amount: number
146
- status: string
147
- entryId: string | null
148
- }
149
-
150
- export interface PeriodCloseStatus {
151
- fiscalPeriodStart: string
152
- fiscalPeriodEnd: string
153
- periodStatus: string
154
- schedules: PeriodCloseItem[]
155
- totalDraft: number
156
- totalPosted: number
157
- }
158
-
159
- /**
160
- * Outcome of an idempotent `createClosingEntry` call.
161
- *
162
- * - `created` — no prior draft, new draft created
163
- * - `unchanged` — prior draft matches current schedule fact, no-op
164
- * - `regenerated` — prior draft was stale, replaced with a fresh one
165
- * - `removed` — prior draft existed but schedule no longer covers this period
166
- * - `skipped` — no prior draft and no in-scope fact; nothing to do
167
- */
168
- export type ClosingEntryOutcome = 'created' | 'unchanged' | 'regenerated' | 'removed' | 'skipped'
169
-
170
- /**
171
- * Result of an idempotent closing-entry call. `entry_id`, `amount`, and
172
- * related fields are null for `removed` and `skipped` outcomes.
173
- */
174
- export interface ClosingEntry {
175
- outcome: ClosingEntryOutcome
176
- entryId: string | null
177
- status: string | null
178
- postingDate: string | null
179
- memo: string | null
180
- debitElementId: string | null
181
- creditElementId: string | null
182
- amount: number | null
183
- reason: string | null
184
- }
185
-
186
- export type LedgerEntryType = 'standard' | 'adjusting' | 'closing' | 'reversing'
187
-
188
- // ── Fiscal calendar types ──────────────────────────────────────────────
189
-
190
- export interface FiscalPeriodSummary {
191
- name: string
192
- startDate: string
193
- endDate: string
194
- status: string
195
- closedAt: string | null
196
- }
197
-
198
- export interface FiscalCalendarState {
199
- graphId: string
200
- fiscalYearStartMonth: number
201
- closedThrough: string | null
202
- closeTarget: string | null
203
- gapPeriods: number
204
- catchUpSequence: string[]
205
- closeableNow: boolean
206
- blockers: string[]
207
- lastCloseAt: string | null
208
- initializedAt: string | null
209
- lastSyncAt: string | null
210
- periods: FiscalPeriodSummary[]
211
- }
212
-
213
- export interface InitializeLedgerOptions {
214
- closedThrough?: string | null
215
- fiscalYearStartMonth?: number
216
- earliestDataPeriod?: string | null
217
- autoSeedSchedules?: boolean
218
- note?: string | null
219
- }
220
-
221
- export interface InitializeLedgerResult {
222
- fiscalCalendar: FiscalCalendarState
223
- periodsCreated: number
224
- warnings: string[]
225
- }
226
-
227
- export interface ClosePeriodOptions {
228
- note?: string | null
229
- allowStaleSync?: boolean
230
- }
231
-
232
- export interface ClosePeriodResult {
233
- period: string
234
- entriesPosted: number
235
- targetAutoAdvanced: boolean
236
- fiscalCalendar: FiscalCalendarState
237
- }
238
-
239
- export interface DraftLineItemView {
240
- lineItemId: string
241
- elementId: string
242
- elementCode: string | null
243
- elementName: string
244
- debitAmount: number
245
- creditAmount: number
246
- description: string | null
247
- }
248
-
249
- export interface DraftEntryView {
250
- entryId: string
251
- postingDate: string
252
- type: string
253
- memo: string | null
254
- provenance: string | null
255
- sourceStructureId: string | null
256
- sourceStructureName: string | null
257
- lineItems: DraftLineItemView[]
258
- totalDebit: number
259
- totalCredit: number
260
- balanced: boolean
261
- }
262
-
263
- export interface PeriodDraftsView {
264
- period: string
265
- periodStart: string
266
- periodEnd: string
267
- draftCount: number
268
- totalDebit: number
269
- totalCredit: number
270
- allBalanced: boolean
271
- drafts: DraftEntryView[]
272
- }
273
-
274
- export interface ManualClosingLineItem {
275
- elementId: string
276
- debitAmount?: number
277
- creditAmount?: number
278
- description?: string | null
279
- }
280
-
281
- export interface CreateManualClosingEntryOptions {
282
- postingDate: string
283
- memo: string
284
- lineItems: ManualClosingLineItem[]
285
- entryType?: LedgerEntryType
286
- }
287
-
288
- export interface TruncateScheduleOptions {
289
- newEndDate: string
290
- reason: string
291
- }
292
-
293
- export interface TruncateScheduleResult {
294
- structureId: string
295
- newEndDate: string
296
- factsDeleted: number
297
- reason: string
298
- }
299
-
300
- export interface CreateScheduleOptions {
301
- name: string
302
- elementIds: string[]
303
- periodStart: string
304
- periodEnd: string
305
- monthlyAmount: number
306
- entryTemplate: {
307
- debitElementId: string
308
- creditElementId: string
309
- entryType?: LedgerEntryType
310
- memoTemplate?: string
311
- }
312
- taxonomyId?: string
313
- scheduleMetadata?: {
314
- method?: string
315
- originalAmount?: number
316
- residualValue?: number
317
- usefulLifeMonths?: number
318
- assetElementId?: string
319
- }
320
- }
321
-
322
- // ── Client ──────────────────────────────────────────────────────────────
323
-
324
- export class LedgerClient {
325
- private config: {
326
- baseUrl: string
327
- credentials?: 'include' | 'same-origin' | 'omit'
328
- headers?: Record<string, string>
329
- token?: string
330
- }
331
-
332
- constructor(config: {
333
- baseUrl: string
334
- credentials?: 'include' | 'same-origin' | 'omit'
335
- headers?: Record<string, string>
336
- token?: string
337
- }) {
338
- this.config = config
339
- }
340
-
341
- // ── Entity ──────────────────────────────────────────────────────────
342
-
343
- /**
344
- * Get the entity (company/organization) for this graph.
345
- */
346
- async getEntity(graphId: string): Promise<LedgerEntity | null> {
347
- const response = await getLedgerEntity({
348
- path: { graph_id: graphId },
349
- })
350
-
351
- if (response.response.status === 404) return null
352
- if (response.error) {
353
- throw new Error(`Get entity failed: ${JSON.stringify(response.error)}`)
354
- }
355
-
356
- const data = response.data as Record<string, unknown>
357
- return {
358
- id: data.id as string,
359
- name: data.name as string,
360
- legalName: (data.legal_name as string) ?? null,
361
- entityType: (data.entity_type as string) ?? null,
362
- industry: (data.industry as string) ?? null,
363
- status: (data.status as string) ?? null,
364
- }
365
- }
366
-
367
- // ── Accounts (Chart of Accounts) ───────────────────────────────────
368
-
369
- /**
370
- * List accounts (flat).
371
- */
372
- async listAccounts(graphId: string): Promise<AccountListResponse> {
373
- const response = await listLedgerAccounts({
374
- path: { graph_id: graphId },
375
- })
376
-
377
- if (response.error) {
378
- throw new Error(`List accounts failed: ${JSON.stringify(response.error)}`)
379
- }
380
-
381
- return response.data as AccountListResponse
382
- }
383
-
384
- /**
385
- * Get the account tree (hierarchical).
386
- */
387
- async getAccountTree(graphId: string): Promise<AccountTreeResponse> {
388
- const response = await getLedgerAccountTree({
389
- path: { graph_id: graphId },
390
- })
391
-
392
- if (response.error) {
393
- throw new Error(`Get account tree failed: ${JSON.stringify(response.error)}`)
394
- }
395
-
396
- return response.data as AccountTreeResponse
397
- }
398
-
399
- // ── Transactions ────────────────────────────────────────────────────
400
-
401
- /**
402
- * List transactions with optional date filters.
403
- */
404
- async listTransactions(
405
- graphId: string,
406
- options?: { startDate?: string; endDate?: string; limit?: number; offset?: number }
407
- ): Promise<LedgerTransactionListResponse> {
408
- const response = await listLedgerTransactions({
409
- path: { graph_id: graphId },
410
- query: {
411
- start_date: options?.startDate,
412
- end_date: options?.endDate,
413
- limit: options?.limit,
414
- offset: options?.offset,
415
- },
416
- })
417
-
418
- if (response.error) {
419
- throw new Error(`List transactions failed: ${JSON.stringify(response.error)}`)
420
- }
421
-
422
- return response.data as LedgerTransactionListResponse
423
- }
424
-
425
- /**
426
- * Get transaction detail with entries and line items.
427
- */
428
- async getTransaction(
429
- graphId: string,
430
- transactionId: string
431
- ): Promise<LedgerTransactionDetailResponse> {
432
- const response = await getLedgerTransaction({
433
- path: { graph_id: graphId, transaction_id: transactionId },
434
- })
435
-
436
- if (response.error) {
437
- throw new Error(`Get transaction failed: ${JSON.stringify(response.error)}`)
438
- }
439
-
440
- return response.data as LedgerTransactionDetailResponse
441
- }
442
-
443
- // ── Trial Balance ──────────────────────────────────────────────────
444
-
445
- /**
446
- * Get trial balance (CoA-level debits/credits).
447
- */
448
- async getTrialBalance(
449
- graphId: string,
450
- options?: { startDate?: string; endDate?: string }
451
- ): Promise<TrialBalanceResponse> {
452
- const response = await getLedgerTrialBalance({
453
- path: { graph_id: graphId },
454
- query: {
455
- start_date: options?.startDate,
456
- end_date: options?.endDate,
457
- },
458
- })
459
-
460
- if (response.error) {
461
- throw new Error(`Get trial balance failed: ${JSON.stringify(response.error)}`)
462
- }
463
-
464
- return response.data as TrialBalanceResponse
465
- }
466
-
467
- /**
468
- * Get mapped trial balance (CoA rolled up to GAAP concepts).
469
- */
470
- async getMappedTrialBalance(
471
- graphId: string,
472
- options?: { mappingId?: string; startDate?: string; endDate?: string }
473
- ): Promise<unknown> {
474
- const response = await getMappedTrialBalance({
475
- path: { graph_id: graphId },
476
- query: {
477
- mapping_id: options?.mappingId,
478
- start_date: options?.startDate,
479
- end_date: options?.endDate,
480
- },
481
- })
482
-
483
- if (response.error) {
484
- throw new Error(`Get mapped trial balance failed: ${JSON.stringify(response.error)}`)
485
- }
486
-
487
- return response.data
488
- }
489
-
490
- // ── Summary ────────────────────────────────────────────────────────
491
-
492
- /**
493
- * Get ledger summary (account count, transaction count, date range).
494
- */
495
- async getSummary(graphId: string): Promise<LedgerSummaryResponse> {
496
- const response = await getLedgerSummary({
497
- path: { graph_id: graphId },
498
- })
499
-
500
- if (response.error) {
501
- throw new Error(`Get summary failed: ${JSON.stringify(response.error)}`)
502
- }
503
-
504
- return response.data as LedgerSummaryResponse
505
- }
506
-
507
- // ── Taxonomy ────────────────────────────────────────────────────────
508
-
509
- /**
510
- * Get the reporting taxonomy (US GAAP seed).
511
- */
512
- async getReportingTaxonomy(graphId: string): Promise<unknown> {
513
- const response = await getReportingTaxonomy({
514
- path: { graph_id: graphId },
515
- })
516
-
517
- if (response.error) {
518
- throw new Error(`Get reporting taxonomy failed: ${JSON.stringify(response.error)}`)
519
- }
520
-
521
- return response.data
522
- }
523
-
524
- /**
525
- * List reporting structures (IS, BS, CF) for a taxonomy.
526
- */
527
- async listStructures(graphId: string, taxonomyId?: string): Promise<Structure[]> {
528
- const response = await listStructures({
529
- path: { graph_id: graphId },
530
- query: taxonomyId ? { taxonomy_id: taxonomyId } : undefined,
531
- })
532
-
533
- if (response.error) {
534
- throw new Error(`List structures failed: ${JSON.stringify(response.error)}`)
535
- }
536
-
537
- const data = response.data as { structures?: Array<Record<string, unknown>> }
538
- return (data.structures ?? []).map((s) => ({
539
- id: s.id as string,
540
- name: s.name as string,
541
- structureType: s.structure_type as string,
542
- }))
543
- }
544
-
545
- /**
546
- * List elements (CoA accounts, GAAP concepts, etc.).
547
- */
548
- async listElements(
549
- graphId: string,
550
- options?: {
551
- taxonomyId?: string
552
- source?: string
553
- classification?: string
554
- isAbstract?: boolean
555
- limit?: number
556
- offset?: number
557
- }
558
- ): Promise<unknown> {
559
- const response = await listElements({
560
- path: { graph_id: graphId },
561
- query: {
562
- taxonomy_id: options?.taxonomyId,
563
- source: options?.source,
564
- classification: options?.classification,
565
- is_abstract: options?.isAbstract,
566
- limit: options?.limit,
567
- offset: options?.offset,
568
- },
569
- })
570
-
571
- if (response.error) {
572
- throw new Error(`List elements failed: ${JSON.stringify(response.error)}`)
573
- }
574
-
575
- return response.data
576
- }
577
-
578
- // ── Mappings ────────────────────────────────────────────────────────
579
-
580
- /**
581
- * Create a new CoA→GAAP mapping structure.
582
- * Returns the created mapping info.
583
- */
584
- async createMappingStructure(
585
- graphId: string,
586
- options?: { name?: string; description?: string; taxonomyId?: string }
587
- ): Promise<MappingInfo> {
588
- const response = await createStructure({
589
- path: { graph_id: graphId },
590
- body: {
591
- name: options?.name ?? 'CoA to Reporting',
592
- description: options?.description ?? 'Map Chart of Accounts to US GAAP reporting concepts',
593
- structure_type: 'coa_mapping',
594
- taxonomy_id: options?.taxonomyId ?? 'tax_usgaap_reporting',
595
- },
596
- })
597
-
598
- if (response.error) {
599
- throw new Error(`Create mapping structure failed: ${JSON.stringify(response.error)}`)
600
- }
601
-
602
- const data = response.data as Record<string, unknown>
603
- return {
604
- id: data.id as string,
605
- name: data.name as string,
606
- description: (data.description as string) ?? null,
607
- structureType: data.structure_type as string,
608
- taxonomyId: data.taxonomy_id as string,
609
- isActive: (data.is_active as boolean) ?? true,
610
- }
611
- }
612
-
613
- /**
614
- * List available CoA→GAAP mapping structures.
615
- */
616
- async listMappings(graphId: string): Promise<MappingInfo[]> {
617
- const response = await listMappings({
618
- path: { graph_id: graphId },
619
- })
620
-
621
- if (response.error) {
622
- throw new Error(`List mappings failed: ${JSON.stringify(response.error)}`)
623
- }
624
-
625
- const data = response.data as { structures?: Array<Record<string, unknown>> }
626
- return (data.structures ?? []).map((s) => ({
627
- id: s.id as string,
628
- name: s.name as string,
629
- description: (s.description as string) ?? null,
630
- structureType: s.structure_type as string,
631
- taxonomyId: s.taxonomy_id as string,
632
- isActive: (s.is_active as boolean) ?? true,
633
- }))
634
- }
635
-
636
- /**
637
- * Get mapping detail — all associations with element names.
638
- */
639
- async getMappingDetail(graphId: string, mappingId: string): Promise<MappingDetailResponse> {
640
- const response = await getMappingDetail({
641
- path: { graph_id: graphId, mapping_id: mappingId },
642
- })
643
-
644
- if (response.error) {
645
- throw new Error(`Get mapping detail failed: ${JSON.stringify(response.error)}`)
646
- }
647
-
648
- return response.data as MappingDetailResponse
649
- }
650
-
651
- /**
652
- * Get mapping coverage — how many CoA elements are mapped.
653
- */
654
- async getMappingCoverage(graphId: string, mappingId: string): Promise<MappingCoverage> {
655
- const response = await getMappingCoverage({
656
- path: { graph_id: graphId, mapping_id: mappingId },
657
- })
658
-
659
- if (response.error) {
660
- throw new Error(`Get mapping coverage failed: ${JSON.stringify(response.error)}`)
661
- }
662
-
663
- const data = response.data as MappingCoverageResponse
664
- return {
665
- totalCoaElements: data.total_coa_elements ?? 0,
666
- mappedCount: data.mapped_count ?? 0,
667
- unmappedCount: data.unmapped_count ?? 0,
668
- coveragePercent: data.coverage_percent ?? 0,
669
- highConfidence: data.high_confidence ?? 0,
670
- mediumConfidence: data.medium_confidence ?? 0,
671
- lowConfidence: data.low_confidence ?? 0,
672
- }
673
- }
674
-
675
- /**
676
- * Create a manual mapping association (CoA element → GAAP element).
677
- */
678
- async createMapping(
679
- graphId: string,
680
- mappingId: string,
681
- fromElementId: string,
682
- toElementId: string,
683
- confidence?: number
684
- ): Promise<void> {
685
- const response = await createMappingAssociation({
686
- path: { graph_id: graphId, mapping_id: mappingId },
687
- body: {
688
- from_element_id: fromElementId,
689
- to_element_id: toElementId,
690
- confidence: confidence ?? 1.0,
691
- },
692
- })
693
-
694
- if (response.error) {
695
- throw new Error(`Create mapping failed: ${JSON.stringify(response.error)}`)
696
- }
697
- }
698
-
699
- /**
700
- * Delete a mapping association.
701
- */
702
- async deleteMapping(graphId: string, mappingId: string, associationId: string): Promise<void> {
703
- const response = await deleteMappingAssociation({
704
- path: { graph_id: graphId, mapping_id: mappingId, association_id: associationId },
705
- })
706
-
707
- if (response.error) {
708
- throw new Error(`Delete mapping failed: ${JSON.stringify(response.error)}`)
709
- }
710
- }
711
-
712
- /**
713
- * Trigger AI auto-mapping (MappingAgent).
714
- * Returns immediately — the agent runs in the background.
715
- */
716
- async autoMap(graphId: string, mappingId: string): Promise<{ operationId?: string }> {
717
- const response = await autoMapElements({
718
- path: { graph_id: graphId, mapping_id: mappingId },
719
- })
720
-
721
- if (response.error) {
722
- throw new Error(`Auto-map failed: ${JSON.stringify(response.error)}`)
723
- }
724
-
725
- const data = response.data as Record<string, unknown> | undefined
726
- return {
727
- operationId: data?.operation_id as string | undefined,
728
- }
729
- }
730
-
731
- // ── Schedules ──────────────────────────────────────────────────────
732
-
733
- /**
734
- * Create a schedule with pre-generated monthly facts.
735
- */
736
- async createSchedule(graphId: string, options: CreateScheduleOptions): Promise<ScheduleCreated> {
737
- const body: CreateScheduleRequest = {
738
- name: options.name,
739
- element_ids: options.elementIds,
740
- period_start: options.periodStart,
741
- period_end: options.periodEnd,
742
- monthly_amount: options.monthlyAmount,
743
- entry_template: {
744
- debit_element_id: options.entryTemplate.debitElementId,
745
- credit_element_id: options.entryTemplate.creditElementId,
746
- entry_type: options.entryTemplate.entryType,
747
- memo_template: options.entryTemplate.memoTemplate,
748
- },
749
- taxonomy_id: options.taxonomyId,
750
- schedule_metadata: options.scheduleMetadata
751
- ? {
752
- method: options.scheduleMetadata.method,
753
- original_amount: options.scheduleMetadata.originalAmount,
754
- residual_value: options.scheduleMetadata.residualValue,
755
- useful_life_months: options.scheduleMetadata.usefulLifeMonths,
756
- asset_element_id: options.scheduleMetadata.assetElementId,
757
- }
758
- : undefined,
759
- }
760
-
761
- const response = await createSchedule({
762
- path: { graph_id: graphId },
763
- body,
764
- })
765
-
766
- if (response.error) {
767
- throw new Error(`Create schedule failed: ${JSON.stringify(response.error)}`)
768
- }
769
-
770
- const data = response.data as ScheduleCreatedResponse
771
- return {
772
- structureId: data.structure_id,
773
- name: data.name,
774
- taxonomyId: data.taxonomy_id,
775
- totalPeriods: data.total_periods,
776
- totalFacts: data.total_facts,
777
- }
778
- }
779
-
780
- /**
781
- * List all schedules for a graph.
782
- */
783
- async listSchedules(graphId: string): Promise<Schedule[]> {
784
- const response = await listSchedules({
785
- path: { graph_id: graphId },
786
- })
787
-
788
- if (response.error) {
789
- throw new Error(`List schedules failed: ${JSON.stringify(response.error)}`)
790
- }
791
-
792
- const data = response.data as ScheduleListResponse
793
- return (data.schedules ?? []).map((s: ScheduleSummaryResponse) => ({
794
- structureId: s.structure_id,
795
- name: s.name,
796
- taxonomyName: s.taxonomy_name,
797
- entryTemplate: s.entry_template ?? null,
798
- scheduleMetadata: s.schedule_metadata ?? null,
799
- totalPeriods: s.total_periods,
800
- periodsWithEntries: s.periods_with_entries,
801
- }))
802
- }
803
-
804
- /**
805
- * Get facts for a schedule, optionally filtered by period.
806
- */
807
- async getScheduleFacts(
808
- graphId: string,
809
- structureId: string,
810
- periodStart?: string,
811
- periodEnd?: string
812
- ): Promise<ScheduleFact[]> {
813
- const response = await getScheduleFacts({
814
- path: { graph_id: graphId, structure_id: structureId },
815
- query: {
816
- period_start: periodStart ?? null,
817
- period_end: periodEnd ?? null,
818
- },
819
- })
820
-
821
- if (response.error) {
822
- throw new Error(`Get schedule facts failed: ${JSON.stringify(response.error)}`)
823
- }
824
-
825
- const data = response.data as ScheduleFactsResponse
826
- return (data.facts ?? []).map((f: ScheduleFactResponse) => ({
827
- elementId: f.element_id,
828
- elementName: f.element_name,
829
- value: f.value,
830
- periodStart: f.period_start,
831
- periodEnd: f.period_end,
832
- }))
833
- }
834
-
835
- /**
836
- * Get close status for all schedules in a fiscal period.
837
- */
838
- async getPeriodCloseStatus(
839
- graphId: string,
840
- periodStart: string,
841
- periodEnd: string
842
- ): Promise<PeriodCloseStatus> {
843
- const response = await getPeriodCloseStatus({
844
- path: { graph_id: graphId },
845
- query: { period_start: periodStart, period_end: periodEnd },
846
- })
847
-
848
- if (response.error) {
849
- throw new Error(`Get period close status failed: ${JSON.stringify(response.error)}`)
850
- }
851
-
852
- const data = response.data as PeriodCloseStatusResponse
853
- return {
854
- fiscalPeriodStart: data.fiscal_period_start,
855
- fiscalPeriodEnd: data.fiscal_period_end,
856
- periodStatus: data.period_status,
857
- schedules: (data.schedules ?? []).map((s: PeriodCloseItemResponse) => ({
858
- structureId: s.structure_id,
859
- structureName: s.structure_name,
860
- amount: s.amount,
861
- status: s.status,
862
- entryId: s.entry_id ?? null,
863
- })),
864
- totalDraft: data.total_draft,
865
- totalPosted: data.total_posted,
866
- }
867
- }
868
-
869
- /**
870
- * Idempotently create (or refresh) a draft closing entry from a schedule's
871
- * facts for a period. The `outcome` field describes what actually happened:
872
- *
873
- * - `created` — new draft
874
- * - `unchanged` — existing draft still matches the schedule; no-op
875
- * - `regenerated` — existing draft was stale; replaced
876
- * - `removed` — schedule no longer covers this period; stale draft deleted
877
- * - `skipped` — no existing draft and no in-scope fact; nothing to do
878
- */
879
- async createClosingEntry(
880
- graphId: string,
881
- structureId: string,
882
- postingDate: string,
883
- periodStart: string,
884
- periodEnd: string,
885
- memo?: string
886
- ): Promise<ClosingEntry> {
887
- const body: CreateClosingEntryRequest = {
888
- posting_date: postingDate,
889
- period_start: periodStart,
890
- period_end: periodEnd,
891
- memo: memo ?? undefined,
892
- }
893
-
894
- const response = await createClosingEntry({
895
- path: { graph_id: graphId, structure_id: structureId },
896
- body,
897
- })
898
-
899
- if (response.error) {
900
- throw new Error(`Create closing entry failed: ${JSON.stringify(response.error)}`)
901
- }
902
-
903
- const data = response.data as ClosingEntryResponse
904
- return toClosingEntry(data)
905
- }
906
-
907
- // ── Closing Book ─────────────────────────────────────────────────────
908
-
909
- /**
910
- * Get all closing book structure categories for the sidebar.
911
- * Returns statements, account rollups, schedules, trial balance,
912
- * and period close grouped into categories.
913
- */
914
- async getClosingBookStructures(graphId: string): Promise<ClosingBookStructuresResponse> {
915
- const response = await getClosingBookStructures({
916
- path: { graph_id: graphId },
917
- })
918
-
919
- if (response.error) {
920
- throw new Error(`Get closing book structures failed: ${JSON.stringify(response.error)}`)
921
- }
922
-
923
- return response.data as ClosingBookStructuresResponse
924
- }
925
-
926
- /**
927
- * Get account rollups — CoA accounts grouped by reporting element with balances.
928
- * Shows how company-specific accounts roll up to standardized reporting lines.
929
- */
930
- async getAccountRollups(
931
- graphId: string,
932
- options?: { mappingId?: string; startDate?: string; endDate?: string }
933
- ): Promise<AccountRollupsResponse> {
934
- const response = await getAccountRollups({
935
- path: { graph_id: graphId },
936
- query: {
937
- mapping_id: options?.mappingId,
938
- start_date: options?.startDate,
939
- end_date: options?.endDate,
940
- },
941
- })
942
-
943
- if (response.error) {
944
- throw new Error(`Get account rollups failed: ${JSON.stringify(response.error)}`)
945
- }
946
-
947
- return response.data as AccountRollupsResponse
948
- }
949
-
950
- // ── Fiscal Calendar ─────────────────────────────────────────────────
951
-
952
- /**
953
- * Initialize the fiscal calendar for a graph. Creates FiscalPeriod rows
954
- * for the data window, sets `closed_through` / `close_target`, and emits
955
- * an `initialized` audit event. Fails with 409 if already initialized.
956
- */
957
- async initializeLedger(
958
- graphId: string,
959
- options?: InitializeLedgerOptions
960
- ): Promise<InitializeLedgerResult> {
961
- const body: InitializeLedgerRequest = {
962
- closed_through: options?.closedThrough ?? null,
963
- fiscal_year_start_month: options?.fiscalYearStartMonth,
964
- earliest_data_period: options?.earliestDataPeriod ?? null,
965
- auto_seed_schedules: options?.autoSeedSchedules,
966
- note: options?.note ?? null,
967
- }
968
-
969
- const response = await initializeLedger({
970
- path: { graph_id: graphId },
971
- body,
972
- })
973
-
974
- if (response.error) {
975
- throw new Error(`Initialize ledger failed: ${JSON.stringify(response.error)}`)
976
- }
977
-
978
- const data = response.data as InitializeLedgerResponse
979
- return {
980
- fiscalCalendar: toFiscalCalendarState(data.fiscal_calendar),
981
- periodsCreated: data.periods_created ?? 0,
982
- warnings: data.warnings ?? [],
983
- }
984
- }
985
-
986
- /**
987
- * Get the current fiscal calendar state — pointers, gap, closeable status.
988
- */
989
- async getFiscalCalendar(graphId: string): Promise<FiscalCalendarState> {
990
- const response = await getFiscalCalendar({
991
- path: { graph_id: graphId },
992
- })
993
-
994
- if (response.error) {
995
- throw new Error(`Get fiscal calendar failed: ${JSON.stringify(response.error)}`)
996
- }
997
-
998
- return toFiscalCalendarState(response.data as FiscalCalendarResponse)
999
- }
1000
-
1001
- /**
1002
- * Set the close target for a graph. Validates that the target is not in
1003
- * the future and not before `closed_through`.
1004
- */
1005
- async setCloseTarget(
1006
- graphId: string,
1007
- period: string,
1008
- note?: string | null
1009
- ): Promise<FiscalCalendarState> {
1010
- const body: SetCloseTargetRequest = {
1011
- period,
1012
- note: note ?? null,
1013
- }
1014
-
1015
- const response = await setCloseTarget({
1016
- path: { graph_id: graphId },
1017
- body,
1018
- })
1019
-
1020
- if (response.error) {
1021
- throw new Error(`Set close target failed: ${JSON.stringify(response.error)}`)
1022
- }
1023
-
1024
- return toFiscalCalendarState(response.data as FiscalCalendarResponse)
1025
- }
1026
-
1027
- /**
1028
- * Close a fiscal period — the final commit action.
1029
- *
1030
- * Validates closeable gates, transitions all draft entries in the period
1031
- * to `posted`, marks the FiscalPeriod closed, and advances `closed_through`
1032
- * (auto-advancing `close_target` when reached).
1033
- */
1034
- async closePeriod(
1035
- graphId: string,
1036
- period: string,
1037
- options?: ClosePeriodOptions
1038
- ): Promise<ClosePeriodResult> {
1039
- const body: ClosePeriodRequest = {
1040
- note: options?.note ?? null,
1041
- allow_stale_sync: options?.allowStaleSync,
1042
- }
1043
-
1044
- const response = await closeFiscalPeriod({
1045
- path: { graph_id: graphId, period },
1046
- body,
1047
- })
1048
-
1049
- if (response.error) {
1050
- throw new Error(`Close period failed: ${JSON.stringify(response.error)}`)
1051
- }
1052
-
1053
- const data = response.data as ClosePeriodResponse
1054
- return {
1055
- period: data.period,
1056
- entriesPosted: data.entries_posted ?? 0,
1057
- targetAutoAdvanced: data.target_auto_advanced ?? false,
1058
- fiscalCalendar: toFiscalCalendarState(data.fiscal_calendar),
1059
- }
1060
- }
1061
-
1062
- /**
1063
- * Reopen a closed fiscal period. Requires a non-empty `reason` for the
1064
- * audit log. Posted entries stay posted; the period transitions to
1065
- * `closing` so the user can post adjustments and re-close.
1066
- */
1067
- async reopenPeriod(
1068
- graphId: string,
1069
- period: string,
1070
- reason: string,
1071
- note?: string | null
1072
- ): Promise<FiscalCalendarState> {
1073
- const body: ReopenPeriodRequest = {
1074
- reason,
1075
- note: note ?? null,
1076
- }
1077
-
1078
- const response = await reopenFiscalPeriod({
1079
- path: { graph_id: graphId, period },
1080
- body,
1081
- })
1082
-
1083
- if (response.error) {
1084
- throw new Error(`Reopen period failed: ${JSON.stringify(response.error)}`)
1085
- }
1086
-
1087
- return toFiscalCalendarState(response.data as FiscalCalendarResponse)
1088
- }
1089
-
1090
- /**
1091
- * List all draft entries in a fiscal period for review before close.
1092
- * Fully expanded with line items, element metadata, and per-entry balance.
1093
- *
1094
- * Pure read — call repeatedly without side effects.
1095
- */
1096
- async listPeriodDrafts(graphId: string, period: string): Promise<PeriodDraftsView> {
1097
- const response = await listPeriodDrafts({
1098
- path: { graph_id: graphId, period },
1099
- })
1100
-
1101
- if (response.error) {
1102
- throw new Error(`List period drafts failed: ${JSON.stringify(response.error)}`)
1103
- }
1104
-
1105
- const data = response.data as PeriodDraftsResponse
1106
- return {
1107
- period: data.period,
1108
- periodStart: data.period_start,
1109
- periodEnd: data.period_end,
1110
- draftCount: data.draft_count,
1111
- totalDebit: data.total_debit,
1112
- totalCredit: data.total_credit,
1113
- allBalanced: data.all_balanced,
1114
- drafts: (data.drafts ?? []).map((d) => ({
1115
- entryId: d.entry_id,
1116
- postingDate: d.posting_date,
1117
- type: d.type,
1118
- memo: d.memo ?? null,
1119
- provenance: d.provenance ?? null,
1120
- sourceStructureId: d.source_structure_id ?? null,
1121
- sourceStructureName: d.source_structure_name ?? null,
1122
- lineItems: d.line_items.map((li) => ({
1123
- lineItemId: li.line_item_id,
1124
- elementId: li.element_id,
1125
- elementCode: li.element_code ?? null,
1126
- elementName: li.element_name,
1127
- debitAmount: li.debit_amount,
1128
- creditAmount: li.credit_amount,
1129
- description: li.description ?? null,
1130
- })),
1131
- totalDebit: d.total_debit,
1132
- totalCredit: d.total_credit,
1133
- balanced: d.balanced,
1134
- })),
1135
- }
1136
- }
1137
-
1138
- // ── Schedule mutations ──────────────────────────────────────────────
1139
-
1140
- /**
1141
- * Truncate a schedule — end it early by deleting facts with
1142
- * `period_start > new_end_date`, along with any stale draft entries they
1143
- * produced. Historical posted facts are preserved.
1144
- *
1145
- * `new_end_date` must be a month-end date (service enforces this).
1146
- */
1147
- async truncateSchedule(
1148
- graphId: string,
1149
- structureId: string,
1150
- options: TruncateScheduleOptions
1151
- ): Promise<TruncateScheduleResult> {
1152
- const body: TruncateScheduleRequest = {
1153
- new_end_date: options.newEndDate,
1154
- reason: options.reason,
1155
- }
1156
-
1157
- const response = await truncateSchedule({
1158
- path: { graph_id: graphId, structure_id: structureId },
1159
- body,
1160
- })
1161
-
1162
- if (response.error) {
1163
- throw new Error(`Truncate schedule failed: ${JSON.stringify(response.error)}`)
1164
- }
1165
-
1166
- const data = response.data as TruncateScheduleResponse
1167
- return {
1168
- structureId: data.structure_id,
1169
- newEndDate: data.new_end_date,
1170
- factsDeleted: data.facts_deleted,
1171
- reason: data.reason,
1172
- }
1173
- }
1174
-
1175
- /**
1176
- * Create a manual draft closing entry with arbitrary balanced line items.
1177
- * Not tied to a schedule — used for disposals, adjustments, and other
1178
- * one-off closing events.
1179
- *
1180
- * Line items must sum to balanced debits/credits. Rejects entries
1181
- * targeting an already-closed period.
1182
- */
1183
- async createManualClosingEntry(
1184
- graphId: string,
1185
- options: CreateManualClosingEntryOptions
1186
- ): Promise<ClosingEntry> {
1187
- const body: CreateManualClosingEntryRequest = {
1188
- posting_date: options.postingDate,
1189
- memo: options.memo,
1190
- entry_type: options.entryType,
1191
- line_items: options.lineItems.map((li) => ({
1192
- element_id: li.elementId,
1193
- debit_amount: li.debitAmount ?? 0,
1194
- credit_amount: li.creditAmount ?? 0,
1195
- description: li.description ?? null,
1196
- })),
1197
- }
1198
-
1199
- const response = await createManualClosingEntry({
1200
- path: { graph_id: graphId },
1201
- body,
1202
- })
1203
-
1204
- if (response.error) {
1205
- throw new Error(`Create manual closing entry failed: ${JSON.stringify(response.error)}`)
1206
- }
1207
-
1208
- return toClosingEntry(response.data as ClosingEntryResponse)
1209
- }
1210
- }
1211
-
1212
- // ── Internal helpers ──────────────────────────────────────────────────
1213
-
1214
- function toClosingEntry(data: ClosingEntryResponse): ClosingEntry {
1215
- return {
1216
- outcome: data.outcome as ClosingEntryOutcome,
1217
- entryId: data.entry_id ?? null,
1218
- status: data.status ?? null,
1219
- postingDate: data.posting_date ?? null,
1220
- memo: data.memo ?? null,
1221
- debitElementId: data.debit_element_id ?? null,
1222
- creditElementId: data.credit_element_id ?? null,
1223
- amount: data.amount ?? null,
1224
- reason: data.reason ?? null,
1225
- }
1226
- }
1227
-
1228
- function toFiscalCalendarState(data: FiscalCalendarResponse): FiscalCalendarState {
1229
- return {
1230
- graphId: data.graph_id,
1231
- fiscalYearStartMonth: data.fiscal_year_start_month,
1232
- closedThrough: data.closed_through ?? null,
1233
- closeTarget: data.close_target ?? null,
1234
- gapPeriods: data.gap_periods ?? 0,
1235
- catchUpSequence: data.catch_up_sequence ?? [],
1236
- closeableNow: data.closeable_now ?? false,
1237
- blockers: data.blockers ?? [],
1238
- lastCloseAt: data.last_close_at ?? null,
1239
- initializedAt: data.initialized_at ?? null,
1240
- lastSyncAt: data.last_sync_at ?? null,
1241
- periods: (data.periods ?? []).map((p) => ({
1242
- name: p.name,
1243
- startDate: p.start_date,
1244
- endDate: p.end_date,
1245
- status: p.status,
1246
- closedAt: p.closed_at ?? null,
1247
- })),
1248
- }
1249
- }