@tailor-platform/erp-kit 0.6.0 → 0.7.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 (290) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +10 -10
  3. package/dist/cli.mjs +407 -69
  4. package/package.json +1 -1
  5. package/skills/erp-kit-app-1-requirements/SKILL.md +33 -17
  6. package/skills/erp-kit-app-2-requirements-review/SKILL.md +12 -0
  7. package/skills/erp-kit-app-3-plan/SKILL.md +18 -4
  8. package/skills/erp-kit-app-3-plan/references/resolver-extraction.md +1 -1
  9. package/skills/erp-kit-app-3-plan/references/screen-extraction.md +1 -1
  10. package/skills/erp-kit-app-4-plan-review/SKILL.md +12 -0
  11. package/skills/erp-kit-app-5-impl-backend/SKILL.md +12 -0
  12. package/skills/erp-kit-app-6-impl-frontend/SKILL.md +12 -0
  13. package/skills/erp-kit-app-7-impl-review/SKILL.md +13 -1
  14. package/skills/erp-kit-app-shared/references/progress-protocol.md +77 -0
  15. package/skills/erp-kit-mock-scenario/SKILL.md +1 -1
  16. package/skills/erp-kit-module-1-requirements/SKILL.md +1 -1
  17. package/skills/erp-kit-module-3-plan/SKILL.md +3 -3
  18. package/skills/erp-kit-module-3-update-plan/SKILL.md +3 -3
  19. package/skills/erp-kit-module-5-impl/SKILL.md +1 -1
  20. package/src/commands/app/index.ts +2 -0
  21. package/src/commands/app/progress/git-context.ts +16 -0
  22. package/src/commands/app/progress/index.ts +45 -0
  23. package/src/commands/app/progress/log.ts +49 -0
  24. package/src/commands/app/progress/progress.test.ts +128 -0
  25. package/src/commands/app/progress/schema-cmd.ts +10 -0
  26. package/src/commands/check.test.ts +4 -4
  27. package/src/commands/lib/discovery.test.ts +5 -7
  28. package/src/commands/lib/discovery.ts +8 -8
  29. package/src/commands/lib/sync-check-source.test.ts +1 -1
  30. package/src/commands/lib/sync-check-source.ts +6 -1
  31. package/src/commands/lib/sync-check-tests.test.ts +43 -0
  32. package/src/commands/lib/sync-check-tests.ts +20 -2
  33. package/src/commands/sync-check.ts +3 -0
  34. package/src/generator/generate-app-code.test.ts +0 -6
  35. package/src/generator/generate-app-code.ts +3 -13
  36. package/src/generator/generate-code.test.ts +10 -40
  37. package/src/generator/generate-code.ts +6 -12
  38. package/src/generator/stub-templates.test.ts +0 -7
  39. package/src/generator/stub-templates.ts +0 -14
  40. package/src/modules/finance-ledger/README.md +50 -0
  41. package/src/modules/finance-ledger/command/.gitkeep +0 -0
  42. package/src/modules/finance-ledger/command/addJournalLine.generated.ts +6 -0
  43. package/src/modules/finance-ledger/command/addJournalLine.test.ts +438 -0
  44. package/src/modules/finance-ledger/command/addJournalLine.ts +122 -0
  45. package/src/modules/finance-ledger/command/approveAndLockPeriod.generated.ts +6 -0
  46. package/src/modules/finance-ledger/command/approveAndLockPeriod.test.ts +107 -0
  47. package/src/modules/finance-ledger/command/approveAndLockPeriod.ts +72 -0
  48. package/src/modules/finance-ledger/command/beginClose.generated.ts +6 -0
  49. package/src/modules/finance-ledger/command/beginClose.test.ts +106 -0
  50. package/src/modules/finance-ledger/command/beginClose.ts +58 -0
  51. package/src/modules/finance-ledger/command/closePeriod.generated.ts +6 -0
  52. package/src/modules/finance-ledger/command/closePeriod.test.ts +87 -0
  53. package/src/modules/finance-ledger/command/closePeriod.ts +44 -0
  54. package/src/modules/finance-ledger/command/createAccountingPeriod.generated.ts +6 -0
  55. package/src/modules/finance-ledger/command/createAccountingPeriod.test.ts +425 -0
  56. package/src/modules/finance-ledger/command/createAccountingPeriod.ts +133 -0
  57. package/src/modules/finance-ledger/command/createFiscalYear.generated.ts +6 -0
  58. package/src/modules/finance-ledger/command/createFiscalYear.test.ts +197 -0
  59. package/src/modules/finance-ledger/command/createFiscalYear.ts +70 -0
  60. package/src/modules/finance-ledger/command/createJournalEntry.generated.ts +6 -0
  61. package/src/modules/finance-ledger/command/createJournalEntry.test.ts +261 -0
  62. package/src/modules/finance-ledger/command/createJournalEntry.ts +121 -0
  63. package/src/modules/finance-ledger/command/deleteAccountingPeriod.generated.ts +6 -0
  64. package/src/modules/finance-ledger/command/deleteAccountingPeriod.test.ts +71 -0
  65. package/src/modules/finance-ledger/command/deleteAccountingPeriod.ts +55 -0
  66. package/src/modules/finance-ledger/command/deleteFiscalYear.generated.ts +6 -0
  67. package/src/modules/finance-ledger/command/deleteFiscalYear.test.ts +38 -0
  68. package/src/modules/finance-ledger/command/deleteFiscalYear.ts +34 -0
  69. package/src/modules/finance-ledger/command/deleteJournalEntry.generated.ts +6 -0
  70. package/src/modules/finance-ledger/command/deleteJournalEntry.test.ts +58 -0
  71. package/src/modules/finance-ledger/command/deleteJournalEntry.ts +43 -0
  72. package/src/modules/finance-ledger/command/executeYearEndClose.generated.ts +6 -0
  73. package/src/modules/finance-ledger/command/executeYearEndClose.test.ts +239 -0
  74. package/src/modules/finance-ledger/command/executeYearEndClose.ts +415 -0
  75. package/src/modules/finance-ledger/command/finalCloseAndLockPeriod.generated.ts +6 -0
  76. package/src/modules/finance-ledger/command/finalCloseAndLockPeriod.test.ts +102 -0
  77. package/src/modules/finance-ledger/command/finalCloseAndLockPeriod.ts +76 -0
  78. package/src/modules/finance-ledger/command/finalizeFinancialStatement.generated.ts +6 -0
  79. package/src/modules/finance-ledger/command/finalizeFinancialStatement.test.ts +73 -0
  80. package/src/modules/finance-ledger/command/finalizeFinancialStatement.ts +73 -0
  81. package/src/modules/finance-ledger/command/generateFinancialStatement.generated.ts +6 -0
  82. package/src/modules/finance-ledger/command/generateFinancialStatement.test.ts +311 -0
  83. package/src/modules/finance-ledger/command/generateFinancialStatement.ts +275 -0
  84. package/src/modules/finance-ledger/command/generatePreliminaryStatements.generated.ts +6 -0
  85. package/src/modules/finance-ledger/command/generatePreliminaryStatements.test.ts +152 -0
  86. package/src/modules/finance-ledger/command/generatePreliminaryStatements.ts +140 -0
  87. package/src/modules/finance-ledger/command/generateTrialBalance.generated.ts +6 -0
  88. package/src/modules/finance-ledger/command/generateTrialBalance.test.ts +439 -0
  89. package/src/modules/finance-ledger/command/generateTrialBalance.ts +268 -0
  90. package/src/modules/finance-ledger/command/initiatePeriodClose.generated.ts +6 -0
  91. package/src/modules/finance-ledger/command/initiatePeriodClose.test.ts +153 -0
  92. package/src/modules/finance-ledger/command/initiatePeriodClose.ts +84 -0
  93. package/src/modules/finance-ledger/command/openForAdvanceEntry.generated.ts +6 -0
  94. package/src/modules/finance-ledger/command/openForAdvanceEntry.test.ts +87 -0
  95. package/src/modules/finance-ledger/command/openForAdvanceEntry.ts +44 -0
  96. package/src/modules/finance-ledger/command/openPeriod.generated.ts +6 -0
  97. package/src/modules/finance-ledger/command/openPeriod.test.ts +90 -0
  98. package/src/modules/finance-ledger/command/openPeriod.ts +44 -0
  99. package/src/modules/finance-ledger/command/permanentlyClosePeriod.generated.ts +6 -0
  100. package/src/modules/finance-ledger/command/permanentlyClosePeriod.test.ts +87 -0
  101. package/src/modules/finance-ledger/command/permanentlyClosePeriod.ts +48 -0
  102. package/src/modules/finance-ledger/command/postAdjustingEntries.generated.ts +6 -0
  103. package/src/modules/finance-ledger/command/postAdjustingEntries.test.ts +392 -0
  104. package/src/modules/finance-ledger/command/postAdjustingEntries.ts +156 -0
  105. package/src/modules/finance-ledger/command/postJournalEntry.generated.ts +6 -0
  106. package/src/modules/finance-ledger/command/postJournalEntry.test.ts +346 -0
  107. package/src/modules/finance-ledger/command/postJournalEntry.ts +160 -0
  108. package/src/modules/finance-ledger/command/processInventoryHandoff.generated.ts +6 -0
  109. package/src/modules/finance-ledger/command/processInventoryHandoff.test.ts +211 -0
  110. package/src/modules/finance-ledger/command/processInventoryHandoff.ts +133 -0
  111. package/src/modules/finance-ledger/command/processManufacturingHandoff.generated.ts +6 -0
  112. package/src/modules/finance-ledger/command/processManufacturingHandoff.test.ts +221 -0
  113. package/src/modules/finance-ledger/command/processManufacturingHandoff.ts +133 -0
  114. package/src/modules/finance-ledger/command/processPurchaseHandoff.generated.ts +6 -0
  115. package/src/modules/finance-ledger/command/processPurchaseHandoff.test.ts +222 -0
  116. package/src/modules/finance-ledger/command/processPurchaseHandoff.ts +133 -0
  117. package/src/modules/finance-ledger/command/processSalesHandoff.generated.ts +6 -0
  118. package/src/modules/finance-ledger/command/processSalesHandoff.test.ts +257 -0
  119. package/src/modules/finance-ledger/command/processSalesHandoff.ts +135 -0
  120. package/src/modules/finance-ledger/command/regenerateFinancialStatement.generated.ts +6 -0
  121. package/src/modules/finance-ledger/command/regenerateFinancialStatement.test.ts +129 -0
  122. package/src/modules/finance-ledger/command/regenerateFinancialStatement.ts +186 -0
  123. package/src/modules/finance-ledger/command/removeJournalLine.generated.ts +6 -0
  124. package/src/modules/finance-ledger/command/removeJournalLine.test.ts +65 -0
  125. package/src/modules/finance-ledger/command/removeJournalLine.ts +39 -0
  126. package/src/modules/finance-ledger/command/reopenPeriod.generated.ts +6 -0
  127. package/src/modules/finance-ledger/command/reopenPeriod.test.ts +87 -0
  128. package/src/modules/finance-ledger/command/reopenPeriod.ts +44 -0
  129. package/src/modules/finance-ledger/command/reverseJournalEntry.generated.ts +6 -0
  130. package/src/modules/finance-ledger/command/reverseJournalEntry.test.ts +337 -0
  131. package/src/modules/finance-ledger/command/reverseJournalEntry.ts +140 -0
  132. package/src/modules/finance-ledger/command/revertSoftLock.generated.ts +6 -0
  133. package/src/modules/finance-ledger/command/revertSoftLock.test.ts +96 -0
  134. package/src/modules/finance-ledger/command/revertSoftLock.ts +67 -0
  135. package/src/modules/finance-ledger/command/updateFiscalYear.generated.ts +6 -0
  136. package/src/modules/finance-ledger/command/updateFiscalYear.test.ts +138 -0
  137. package/src/modules/finance-ledger/command/updateFiscalYear.ts +85 -0
  138. package/src/modules/finance-ledger/command/updateJournalEntry.generated.ts +6 -0
  139. package/src/modules/finance-ledger/command/updateJournalEntry.test.ts +195 -0
  140. package/src/modules/finance-ledger/command/updateJournalEntry.ts +86 -0
  141. package/src/modules/finance-ledger/command/updateJournalLine.generated.ts +6 -0
  142. package/src/modules/finance-ledger/command/updateJournalLine.test.ts +385 -0
  143. package/src/modules/finance-ledger/command/updateJournalLine.ts +155 -0
  144. package/src/modules/finance-ledger/command/verifySubledgerTransfers.generated.ts +6 -0
  145. package/src/modules/finance-ledger/command/verifySubledgerTransfers.test.ts +201 -0
  146. package/src/modules/finance-ledger/command/verifySubledgerTransfers.ts +113 -0
  147. package/src/modules/finance-ledger/command/verifyTrialBalance.generated.ts +6 -0
  148. package/src/modules/finance-ledger/command/verifyTrialBalance.test.ts +136 -0
  149. package/src/modules/finance-ledger/command/verifyTrialBalance.ts +97 -0
  150. package/src/modules/finance-ledger/db/.gitkeep +0 -0
  151. package/src/modules/finance-ledger/db/accountingPeriod.ts +58 -0
  152. package/src/modules/finance-ledger/db/financialStatement.ts +92 -0
  153. package/src/modules/finance-ledger/db/financialStatementLineItem.ts +76 -0
  154. package/src/modules/finance-ledger/db/fiscalYear.ts +41 -0
  155. package/src/modules/finance-ledger/db/journalEntry.ts +101 -0
  156. package/src/modules/finance-ledger/db/journalLine.ts +64 -0
  157. package/src/modules/finance-ledger/db/periodClose.ts +97 -0
  158. package/src/modules/finance-ledger/db/trialBalance.ts +63 -0
  159. package/src/modules/finance-ledger/db/trialBalanceLine.ts +63 -0
  160. package/src/modules/finance-ledger/docs/commands/AddJournalLine.md +74 -0
  161. package/src/modules/finance-ledger/docs/commands/ApproveAndLockPeriod.md +53 -0
  162. package/src/modules/finance-ledger/docs/commands/BeginClose.md +47 -0
  163. package/src/modules/finance-ledger/docs/commands/ClosePeriod.md +45 -0
  164. package/src/modules/finance-ledger/docs/commands/CreateAccountingPeriod.md +69 -0
  165. package/src/modules/finance-ledger/docs/commands/CreateFiscalYear.md +56 -0
  166. package/src/modules/finance-ledger/docs/commands/CreateJournalEntry.md +63 -0
  167. package/src/modules/finance-ledger/docs/commands/DeleteAccountingPeriod.md +46 -0
  168. package/src/modules/finance-ledger/docs/commands/DeleteFiscalYear.md +40 -0
  169. package/src/modules/finance-ledger/docs/commands/DeleteJournalEntry.md +44 -0
  170. package/src/modules/finance-ledger/docs/commands/ExecuteYearEndClose.md +81 -0
  171. package/src/modules/finance-ledger/docs/commands/FinalCloseAndLockPeriod.md +49 -0
  172. package/src/modules/finance-ledger/docs/commands/FinalizeFinancialStatement.md +43 -0
  173. package/src/modules/finance-ledger/docs/commands/GenerateFinancialStatement.md +86 -0
  174. package/src/modules/finance-ledger/docs/commands/GeneratePreliminaryStatements.md +53 -0
  175. package/src/modules/finance-ledger/docs/commands/GenerateTrialBalance.md +75 -0
  176. package/src/modules/finance-ledger/docs/commands/InitiatePeriodClose.md +58 -0
  177. package/src/modules/finance-ledger/docs/commands/OpenForAdvanceEntry.md +44 -0
  178. package/src/modules/finance-ledger/docs/commands/OpenPeriod.md +45 -0
  179. package/src/modules/finance-ledger/docs/commands/PermanentlyClosePeriod.md +45 -0
  180. package/src/modules/finance-ledger/docs/commands/PostAdjustingEntries.md +61 -0
  181. package/src/modules/finance-ledger/docs/commands/PostJournalEntry.md +81 -0
  182. package/src/modules/finance-ledger/docs/commands/ProcessInventoryHandoff.md +72 -0
  183. package/src/modules/finance-ledger/docs/commands/ProcessManufacturingHandoff.md +68 -0
  184. package/src/modules/finance-ledger/docs/commands/ProcessPurchaseHandoff.md +68 -0
  185. package/src/modules/finance-ledger/docs/commands/ProcessSalesHandoff.md +71 -0
  186. package/src/modules/finance-ledger/docs/commands/RegenerateFinancialStatement.md +60 -0
  187. package/src/modules/finance-ledger/docs/commands/RemoveJournalLine.md +42 -0
  188. package/src/modules/finance-ledger/docs/commands/ReopenPeriod.md +45 -0
  189. package/src/modules/finance-ledger/docs/commands/ReverseJournalEntry.md +62 -0
  190. package/src/modules/finance-ledger/docs/commands/RevertSoftLock.md +49 -0
  191. package/src/modules/finance-ledger/docs/commands/UpdateFiscalYear.md +60 -0
  192. package/src/modules/finance-ledger/docs/commands/UpdateJournalEntry.md +50 -0
  193. package/src/modules/finance-ledger/docs/commands/UpdateJournalLine.md +61 -0
  194. package/src/modules/finance-ledger/docs/commands/VerifySubledgerTransfers.md +59 -0
  195. package/src/modules/finance-ledger/docs/commands/VerifyTrialBalance.md +53 -0
  196. package/src/modules/finance-ledger/docs/features/accounting-period-management.md +110 -0
  197. package/src/modules/finance-ledger/docs/features/financial-statement-generation.md +115 -0
  198. package/src/modules/finance-ledger/docs/features/journal-entry-management.md +138 -0
  199. package/src/modules/finance-ledger/docs/features/period-end-close.md +102 -0
  200. package/src/modules/finance-ledger/docs/features/subledger-integration.md +141 -0
  201. package/src/modules/finance-ledger/docs/features/trial-balance.md +99 -0
  202. package/src/modules/finance-ledger/docs/features/year-end-close.md +84 -0
  203. package/src/modules/finance-ledger/docs/models/AccountingPeriod.md +71 -0
  204. package/src/modules/finance-ledger/docs/models/FinancialStatement.md +76 -0
  205. package/src/modules/finance-ledger/docs/models/FinancialStatementLineItem.md +41 -0
  206. package/src/modules/finance-ledger/docs/models/FiscalYear.md +41 -0
  207. package/src/modules/finance-ledger/docs/models/JournalEntry.md +80 -0
  208. package/src/modules/finance-ledger/docs/models/JournalLine.md +47 -0
  209. package/src/modules/finance-ledger/docs/models/PeriodClose.md +83 -0
  210. package/src/modules/finance-ledger/docs/models/TrialBalance.md +56 -0
  211. package/src/modules/finance-ledger/docs/models/TrialBalanceLine.md +37 -0
  212. package/src/modules/finance-ledger/docs/queries/GetAccountingPeriod.md +35 -0
  213. package/src/modules/finance-ledger/docs/queries/GetFinancialStatement.md +38 -0
  214. package/src/modules/finance-ledger/docs/queries/GetFiscalYear.md +35 -0
  215. package/src/modules/finance-ledger/docs/queries/GetJournalEntry.md +37 -0
  216. package/src/modules/finance-ledger/docs/queries/GetPeriodByDate.md +38 -0
  217. package/src/modules/finance-ledger/docs/queries/GetPeriodClose.md +36 -0
  218. package/src/modules/finance-ledger/docs/queries/GetSubledgerTransferStatus.md +45 -0
  219. package/src/modules/finance-ledger/docs/queries/GetTrialBalance.md +38 -0
  220. package/src/modules/finance-ledger/docs/queries/ListAccountingPeriods.md +46 -0
  221. package/src/modules/finance-ledger/docs/queries/ListFinancialStatements.md +46 -0
  222. package/src/modules/finance-ledger/docs/queries/ListFiscalYears.md +42 -0
  223. package/src/modules/finance-ledger/docs/queries/ListJournalEntries.md +48 -0
  224. package/src/modules/finance-ledger/docs/queries/ListPeriodCloses.md +46 -0
  225. package/src/modules/finance-ledger/docs/queries/ListTrialBalances.md +51 -0
  226. package/src/modules/finance-ledger/executor/.gitkeep +0 -0
  227. package/src/modules/finance-ledger/generated/enums.ts +109 -0
  228. package/src/modules/finance-ledger/generated/kysely-tailordb.ts +202 -0
  229. package/src/modules/finance-ledger/index.ts +2 -0
  230. package/src/modules/finance-ledger/lib/_db_deps.ts +56 -0
  231. package/src/modules/finance-ledger/lib/errors.generated.ts +332 -0
  232. package/src/modules/finance-ledger/lib/permissions.generated.ts +41 -0
  233. package/src/modules/finance-ledger/lib/types.ts +66 -0
  234. package/src/modules/finance-ledger/module.ts +262 -0
  235. package/src/modules/finance-ledger/package.json +26 -0
  236. package/src/modules/finance-ledger/permissions.ts +3 -0
  237. package/src/modules/finance-ledger/query/.gitkeep +0 -0
  238. package/src/modules/finance-ledger/query/getAccountingPeriod.generated.ts +5 -0
  239. package/src/modules/finance-ledger/query/getAccountingPeriod.test.ts +31 -0
  240. package/src/modules/finance-ledger/query/getAccountingPeriod.ts +21 -0
  241. package/src/modules/finance-ledger/query/getFinancialStatement.generated.ts +5 -0
  242. package/src/modules/finance-ledger/query/getFinancialStatement.test.ts +35 -0
  243. package/src/modules/finance-ledger/query/getFinancialStatement.ts +29 -0
  244. package/src/modules/finance-ledger/query/getFiscalYear.generated.ts +5 -0
  245. package/src/modules/finance-ledger/query/getFiscalYear.test.ts +31 -0
  246. package/src/modules/finance-ledger/query/getFiscalYear.ts +21 -0
  247. package/src/modules/finance-ledger/query/getJournalEntry.generated.ts +5 -0
  248. package/src/modules/finance-ledger/query/getJournalEntry.test.ts +35 -0
  249. package/src/modules/finance-ledger/query/getJournalEntry.ts +29 -0
  250. package/src/modules/finance-ledger/query/getPeriodByDate.generated.ts +5 -0
  251. package/src/modules/finance-ledger/query/getPeriodByDate.test.ts +53 -0
  252. package/src/modules/finance-ledger/query/getPeriodByDate.ts +27 -0
  253. package/src/modules/finance-ledger/query/getPeriodClose.generated.ts +5 -0
  254. package/src/modules/finance-ledger/query/getPeriodClose.test.ts +31 -0
  255. package/src/modules/finance-ledger/query/getPeriodClose.ts +21 -0
  256. package/src/modules/finance-ledger/query/getSubledgerTransferStatus.generated.ts +5 -0
  257. package/src/modules/finance-ledger/query/getSubledgerTransferStatus.test.ts +101 -0
  258. package/src/modules/finance-ledger/query/getSubledgerTransferStatus.ts +68 -0
  259. package/src/modules/finance-ledger/query/getTrialBalance.generated.ts +5 -0
  260. package/src/modules/finance-ledger/query/getTrialBalance.test.ts +33 -0
  261. package/src/modules/finance-ledger/query/getTrialBalance.ts +30 -0
  262. package/src/modules/finance-ledger/query/listAccountingPeriods.generated.ts +5 -0
  263. package/src/modules/finance-ledger/query/listAccountingPeriods.test.ts +81 -0
  264. package/src/modules/finance-ledger/query/listAccountingPeriods.ts +61 -0
  265. package/src/modules/finance-ledger/query/listFinancialStatements.generated.ts +5 -0
  266. package/src/modules/finance-ledger/query/listFinancialStatements.test.ts +76 -0
  267. package/src/modules/finance-ledger/query/listFinancialStatements.ts +62 -0
  268. package/src/modules/finance-ledger/query/listFiscalYears.generated.ts +5 -0
  269. package/src/modules/finance-ledger/query/listFiscalYears.test.ts +63 -0
  270. package/src/modules/finance-ledger/query/listFiscalYears.ts +45 -0
  271. package/src/modules/finance-ledger/query/listJournalEntries.generated.ts +5 -0
  272. package/src/modules/finance-ledger/query/listJournalEntries.test.ts +91 -0
  273. package/src/modules/finance-ledger/query/listJournalEntries.ts +64 -0
  274. package/src/modules/finance-ledger/query/listPeriodCloses.generated.ts +5 -0
  275. package/src/modules/finance-ledger/query/listPeriodCloses.test.ts +63 -0
  276. package/src/modules/finance-ledger/query/listPeriodCloses.ts +64 -0
  277. package/src/modules/finance-ledger/query/listTrialBalances.generated.ts +5 -0
  278. package/src/modules/finance-ledger/query/listTrialBalances.test.ts +78 -0
  279. package/src/modules/finance-ledger/query/listTrialBalances.ts +56 -0
  280. package/src/modules/finance-ledger/seed/index.ts +19 -0
  281. package/src/modules/finance-ledger/tailor.config.ts +13 -0
  282. package/src/modules/finance-ledger/tailor.d.ts +13 -0
  283. package/src/modules/finance-ledger/testing/commandTestUtils.ts +35 -0
  284. package/src/modules/finance-ledger/testing/fixtures.ts +382 -0
  285. package/src/modules/finance-ledger/tsconfig.json +16 -0
  286. package/src/progress/schema.test.ts +161 -0
  287. package/src/progress/schema.ts +316 -0
  288. package/templates/scaffold/app/backend/package.json +1 -3
  289. package/templates/scaffold/app/backend/vitest.config.ts +4 -21
  290. package/src/generator/generate-stubs.ts +0 -35
@@ -0,0 +1,73 @@
1
+ import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";
2
+ import type { Transaction } from "../generated/kysely-tailordb";
3
+ import {
4
+ FinancialStatementNotFoundError,
5
+ InvalidStatusTransitionError,
6
+ } from "../lib/errors.generated";
7
+
8
+ export interface FinalizeFinancialStatementInput {
9
+ id: string;
10
+ }
11
+
12
+ interface AuditEntry {
13
+ type: string;
14
+ from?: string;
15
+ to?: string;
16
+ actorId?: string;
17
+ }
18
+
19
+ /**
20
+ * Function: finalizeFinancialStatement
21
+ *
22
+ * Transitions a financial statement from DRAFT to FINALIZED status.
23
+ * Once finalized, the statement becomes immutable and cannot be
24
+ * modified or regenerated.
25
+ */
26
+ export async function run(
27
+ db: Transaction,
28
+ input: FinalizeFinancialStatementInput,
29
+ ctx: CommandContext,
30
+ ) {
31
+ const { id } = input;
32
+ const auditTrail: AuditEntry[] = [];
33
+
34
+ // 1. Find FinancialStatement by id with forUpdate()
35
+ const financialStatement = await db
36
+ .selectFrom("FinancialStatement")
37
+ .selectAll()
38
+ .where("id", "=", id)
39
+ .forUpdate()
40
+ .executeTakeFirst();
41
+
42
+ if (!financialStatement) {
43
+ return err(new FinancialStatementNotFoundError(id));
44
+ }
45
+
46
+ // 2. Validate status is DRAFT
47
+ if (financialStatement.status !== "DRAFT") {
48
+ return err(new InvalidStatusTransitionError(id));
49
+ }
50
+
51
+ // 3. Update to FINALIZED, set finalizedAt to now
52
+ const now = new Date();
53
+ const updatedStatement = await db
54
+ .updateTable("FinancialStatement")
55
+ .set({
56
+ status: "FINALIZED",
57
+ finalizedAt: now,
58
+ updatedAt: now,
59
+ })
60
+ .where("id", "=", id)
61
+ .returningAll()
62
+ .executeTakeFirst();
63
+
64
+ // 4. Record audit event
65
+ auditTrail.push({
66
+ type: "STATUS_TRANSITION",
67
+ from: "DRAFT",
68
+ to: "FINALIZED",
69
+ actorId: ctx.actorId,
70
+ });
71
+
72
+ return ok({ financialStatement: updatedStatement!, auditTrail });
73
+ }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { defineCommand } from "@tailor-platform/erp-kit/module";
3
+ import { permissions } from "../lib/permissions.generated";
4
+ import { run } from "./generateFinancialStatement";
5
+
6
+ export const generateFinancialStatement = defineCommand(permissions.generateFinancialStatement, run);
@@ -0,0 +1,311 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ CompanyNotFoundError,
6
+ ChartOfAccountsNotFoundError,
7
+ InvalidStatementTypeError,
8
+ InvalidReportingParametersError,
9
+ NoTrialBalanceDataError,
10
+ ComparativeDataUnavailableError,
11
+ } from "../lib/errors.generated";
12
+ import {
13
+ baseCompany,
14
+ baseChartOfAccounts,
15
+ baseTrialBalance,
16
+ baseTrialBalanceLine,
17
+ baseFinancialStatement,
18
+ baseAccount,
19
+ revenueAccount,
20
+ expenseAccount,
21
+ } from "../testing/fixtures";
22
+ import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
23
+ import { run, type GenerateFinancialStatementInput } from "./generateFinancialStatement";
24
+
25
+ describe("generateFinancialStatement", () => {
26
+ const balanceSheetInput: GenerateFinancialStatementInput = {
27
+ companyId: baseCompany.id,
28
+ chartOfAccountsId: baseChartOfAccounts.id,
29
+ trialBalanceId: baseTrialBalance.id,
30
+ statementType: "BALANCE_SHEET",
31
+ reportingDate: new Date("2024-01-31"),
32
+ };
33
+
34
+ const profitAndLossInput: GenerateFinancialStatementInput = {
35
+ companyId: baseCompany.id,
36
+ chartOfAccountsId: baseChartOfAccounts.id,
37
+ trialBalanceId: baseTrialBalance.id,
38
+ statementType: "PROFIT_AND_LOSS",
39
+ startDate: new Date("2024-01-01"),
40
+ endDate: new Date("2024-01-31"),
41
+ };
42
+
43
+ it("returns error when company does not exist", async () => {
44
+ const { db, spies } = createMockDb<Transaction>();
45
+ spies.select.mockReturnValueOnce(undefined);
46
+
47
+ const result = await run(db, { ...balanceSheetInput, companyId: "missing" }, commandCtx);
48
+
49
+ expectErr(result, CompanyNotFoundError);
50
+ });
51
+
52
+ it("returns error when company is not ACTIVE", async () => {
53
+ const { db, spies } = createMockDb<Transaction>();
54
+ spies.select.mockReturnValueOnce({ ...baseCompany, status: "INACTIVE" });
55
+
56
+ const result = await run(db, balanceSheetInput, commandCtx);
57
+
58
+ expectErr(result, CompanyNotFoundError);
59
+ });
60
+
61
+ it("returns error when CoA does not exist", async () => {
62
+ const { db, spies } = createMockDb<Transaction>();
63
+ spies.select
64
+ .mockReturnValueOnce(baseCompany) // company lookup
65
+ .mockReturnValueOnce(undefined); // CoA lookup
66
+
67
+ const result = await run(db, balanceSheetInput, commandCtx);
68
+
69
+ expectErr(result, ChartOfAccountsNotFoundError);
70
+ });
71
+
72
+ it("returns error when CoA is not ACTIVE", async () => {
73
+ const { db, spies } = createMockDb<Transaction>();
74
+ spies.select
75
+ .mockReturnValueOnce(baseCompany)
76
+ .mockReturnValueOnce({ ...baseChartOfAccounts, status: "INACTIVE" });
77
+
78
+ const result = await run(db, balanceSheetInput, commandCtx);
79
+
80
+ expectErr(result, ChartOfAccountsNotFoundError);
81
+ });
82
+
83
+ it("returns error for invalid statement type", async () => {
84
+ const { db, spies } = createMockDb<Transaction>();
85
+ spies.select.mockReturnValueOnce(baseCompany).mockReturnValueOnce(baseChartOfAccounts);
86
+
87
+ const result = await run(
88
+ db,
89
+ { ...balanceSheetInput, statementType: "INVALID_TYPE" },
90
+ commandCtx,
91
+ );
92
+
93
+ expectErr(result, InvalidStatementTypeError);
94
+ });
95
+
96
+ it("returns error when BALANCE_SHEET is missing reportingDate", async () => {
97
+ const { db, spies } = createMockDb<Transaction>();
98
+ spies.select.mockReturnValueOnce(baseCompany).mockReturnValueOnce(baseChartOfAccounts);
99
+
100
+ const input: GenerateFinancialStatementInput = {
101
+ ...balanceSheetInput,
102
+ reportingDate: undefined,
103
+ };
104
+ const result = await run(db, input, commandCtx);
105
+
106
+ expectErr(result, InvalidReportingParametersError);
107
+ });
108
+
109
+ it("returns error when PROFIT_AND_LOSS is missing date range", async () => {
110
+ const { db, spies } = createMockDb<Transaction>();
111
+ spies.select.mockReturnValueOnce(baseCompany).mockReturnValueOnce(baseChartOfAccounts);
112
+
113
+ const input: GenerateFinancialStatementInput = {
114
+ companyId: baseCompany.id,
115
+ chartOfAccountsId: baseChartOfAccounts.id,
116
+ trialBalanceId: baseTrialBalance.id,
117
+ statementType: "PROFIT_AND_LOSS",
118
+ };
119
+ const result = await run(db, input, commandCtx);
120
+
121
+ expectErr(result, InvalidReportingParametersError);
122
+ });
123
+
124
+ it("returns error when CASH_FLOW is missing cashFlowMethod", async () => {
125
+ const { db, spies } = createMockDb<Transaction>();
126
+ spies.select.mockReturnValueOnce(baseCompany).mockReturnValueOnce(baseChartOfAccounts);
127
+
128
+ const input: GenerateFinancialStatementInput = {
129
+ companyId: baseCompany.id,
130
+ chartOfAccountsId: baseChartOfAccounts.id,
131
+ trialBalanceId: baseTrialBalance.id,
132
+ statementType: "CASH_FLOW",
133
+ startDate: new Date("2024-01-01"),
134
+ endDate: new Date("2024-01-31"),
135
+ };
136
+ const result = await run(db, input, commandCtx);
137
+
138
+ expectErr(result, InvalidReportingParametersError);
139
+ });
140
+
141
+ it("returns error when trial balance does not exist", async () => {
142
+ const { db, spies } = createMockDb<Transaction>();
143
+ spies.select
144
+ .mockReturnValueOnce(baseCompany) // company
145
+ .mockReturnValueOnce(baseChartOfAccounts) // CoA
146
+ .mockReturnValueOnce(undefined); // trial balance
147
+
148
+ const result = await run(db, balanceSheetInput, commandCtx);
149
+
150
+ expectErr(result, NoTrialBalanceDataError);
151
+ });
152
+
153
+ it("returns error when comparative trial balance does not exist", async () => {
154
+ const { db, spies } = createMockDb<Transaction>();
155
+ spies.select
156
+ .mockReturnValueOnce(baseCompany) // company
157
+ .mockReturnValueOnce(baseChartOfAccounts) // CoA
158
+ .mockReturnValueOnce(baseTrialBalance) // trial balance
159
+ .mockReturnValueOnce(undefined); // comparative trial balance
160
+
161
+ const result = await run(
162
+ db,
163
+ { ...balanceSheetInput, comparativePeriodTrialBalanceId: "missing-comparative" },
164
+ commandCtx,
165
+ );
166
+
167
+ expectErr(result, ComparativeDataUnavailableError);
168
+ });
169
+
170
+ it("successfully generates a BALANCE_SHEET financial statement", async () => {
171
+ const { db, spies } = createMockDb<Transaction>();
172
+ spies.select
173
+ .mockReturnValueOnce(baseCompany) // company
174
+ .mockReturnValueOnce(baseChartOfAccounts) // CoA
175
+ .mockReturnValueOnce(baseTrialBalance) // trial balance
176
+ .mockReturnValueOnce([baseTrialBalanceLine]) // trial balance lines (execute)
177
+ .mockReturnValueOnce(baseAccount); // account lookup for line
178
+ spies.insert
179
+ .mockReturnValueOnce(baseFinancialStatement) // FinancialStatement insert
180
+ .mockReturnValueOnce({
181
+ ...baseTrialBalanceLine,
182
+ id: "fs-line-1",
183
+ financialStatementId: baseFinancialStatement.id,
184
+ }) // DETAIL line item insert
185
+ .mockReturnValueOnce({
186
+ id: "fs-line-subtotal-1",
187
+ financialStatementId: baseFinancialStatement.id,
188
+ lineType: "SUBTOTAL",
189
+ }); // SUBTOTAL line item insert
190
+
191
+ const result = await run(db, balanceSheetInput, commandCtx);
192
+
193
+ const value = expectOk(result);
194
+ expect(value.financialStatement).toEqual(baseFinancialStatement);
195
+ expect(value.auditTrail).toBeDefined();
196
+ expect(value.auditTrail.length).toBeGreaterThan(0);
197
+ });
198
+
199
+ it("successfully generates a PROFIT_AND_LOSS financial statement", async () => {
200
+ const plTrialBalanceLine = {
201
+ ...baseTrialBalanceLine,
202
+ id: "tb-line-revenue",
203
+ accountId: revenueAccount.id,
204
+ accountCode: revenueAccount.code,
205
+ accountName: revenueAccount.name,
206
+ closingBalance: 8000,
207
+ };
208
+ const plExpenseLine = {
209
+ ...baseTrialBalanceLine,
210
+ id: "tb-line-expense",
211
+ accountId: expenseAccount.id,
212
+ accountCode: expenseAccount.code,
213
+ accountName: expenseAccount.name,
214
+ closingBalance: 3000,
215
+ };
216
+ const plFinancialStatement = {
217
+ ...baseFinancialStatement,
218
+ id: "financial-statement-pl",
219
+ statementType: "PROFIT_AND_LOSS",
220
+ reportingDate: null,
221
+ startDate: new Date("2024-01-01"),
222
+ endDate: new Date("2024-01-31"),
223
+ };
224
+
225
+ const { db, spies } = createMockDb<Transaction>();
226
+ spies.select
227
+ .mockReturnValueOnce(baseCompany) // company
228
+ .mockReturnValueOnce(baseChartOfAccounts) // CoA
229
+ .mockReturnValueOnce(baseTrialBalance) // trial balance
230
+ .mockReturnValueOnce([plTrialBalanceLine, plExpenseLine]) // trial balance lines
231
+ .mockReturnValueOnce(revenueAccount) // account lookup for revenue line
232
+ .mockReturnValueOnce(expenseAccount); // account lookup for expense line
233
+ spies.insert
234
+ .mockReturnValueOnce(plFinancialStatement) // FinancialStatement insert
235
+ .mockReturnValueOnce({}) // DETAIL line item 1 (revenue)
236
+ .mockReturnValueOnce({}) // DETAIL line item 2 (expense)
237
+ .mockReturnValueOnce({}) // SUBTOTAL line item for Revenue
238
+ .mockReturnValueOnce({}); // SUBTOTAL line item for Expenses
239
+
240
+ const result = await run(db, profitAndLossInput, commandCtx);
241
+
242
+ const value = expectOk(result);
243
+ expect(value.financialStatement.statementType).toBe("PROFIT_AND_LOSS");
244
+ });
245
+
246
+ it("returns error when trial balance has no lines", async () => {
247
+ const { db, spies } = createMockDb<Transaction>();
248
+ spies.select
249
+ .mockReturnValueOnce(baseCompany) // company
250
+ .mockReturnValueOnce(baseChartOfAccounts) // CoA
251
+ .mockReturnValueOnce(baseTrialBalance) // trial balance exists
252
+ .mockReturnValueOnce([]); // but has no lines
253
+
254
+ const result = await run(db, balanceSheetInput, commandCtx);
255
+
256
+ expectErr(result, NoTrialBalanceDataError);
257
+ });
258
+
259
+ it("emits audit event recording the generation", async () => {
260
+ const { db, spies } = createMockDb<Transaction>();
261
+ spies.select
262
+ .mockReturnValueOnce(baseCompany) // company
263
+ .mockReturnValueOnce(baseChartOfAccounts) // CoA
264
+ .mockReturnValueOnce(baseTrialBalance) // trial balance
265
+ .mockReturnValueOnce([baseTrialBalanceLine]) // trial balance lines
266
+ .mockReturnValueOnce(baseAccount); // account lookup for line
267
+ spies.insert
268
+ .mockReturnValueOnce(baseFinancialStatement) // FinancialStatement insert
269
+ .mockReturnValueOnce({}) // DETAIL line item
270
+ .mockReturnValueOnce({}); // SUBTOTAL line item
271
+
272
+ const result = await run(db, balanceSheetInput, commandCtx);
273
+
274
+ const value = expectOk(result);
275
+ expect(value.auditTrail).toEqual([
276
+ {
277
+ type: "FINANCIAL_STATEMENT_GENERATED",
278
+ statementType: "BALANCE_SHEET",
279
+ actorId: commandCtx.actorId,
280
+ },
281
+ ]);
282
+ });
283
+
284
+ it("generates subtotal lines for each section", async () => {
285
+ const { db, spies } = createMockDb<Transaction>();
286
+ spies.select
287
+ .mockReturnValueOnce(baseCompany) // company
288
+ .mockReturnValueOnce(baseChartOfAccounts) // CoA
289
+ .mockReturnValueOnce(baseTrialBalance) // trial balance
290
+ .mockReturnValueOnce([baseTrialBalanceLine]) // trial balance lines
291
+ .mockReturnValueOnce(baseAccount); // account lookup for line
292
+ const subtotalLineItem = {
293
+ id: "fs-line-subtotal-1",
294
+ financialStatementId: baseFinancialStatement.id,
295
+ lineType: "SUBTOTAL",
296
+ label: "Total Assets",
297
+ amount: 3000,
298
+ sectionType: "Assets",
299
+ };
300
+ spies.insert
301
+ .mockReturnValueOnce(baseFinancialStatement) // FinancialStatement insert
302
+ .mockReturnValueOnce({}) // DETAIL line item
303
+ .mockReturnValueOnce(subtotalLineItem); // SUBTOTAL line item
304
+
305
+ const result = await run(db, balanceSheetInput, commandCtx);
306
+
307
+ expectOk(result);
308
+ // Verify insert was called for both DETAIL and SUBTOTAL lines (2 line item inserts)
309
+ expect(spies.insert).toHaveBeenCalledTimes(3); // 1 statement + 2 line items
310
+ });
311
+ });
@@ -0,0 +1,275 @@
1
+ import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";
2
+ import type { Transaction } from "../generated/kysely-tailordb";
3
+ import {
4
+ CompanyNotFoundError,
5
+ ChartOfAccountsNotFoundError,
6
+ InvalidStatementTypeError,
7
+ InvalidReportingParametersError,
8
+ NoTrialBalanceDataError,
9
+ ComparativeDataUnavailableError,
10
+ } from "../lib/errors.generated";
11
+
12
+ export interface GenerateFinancialStatementInput {
13
+ companyId: string;
14
+ chartOfAccountsId: string;
15
+ trialBalanceId: string;
16
+ statementType: string;
17
+ reportingDate?: Date;
18
+ startDate?: Date;
19
+ endDate?: Date;
20
+ cashFlowMethod?: string;
21
+ comparativePeriodTrialBalanceId?: string;
22
+ }
23
+
24
+ const VALID_STATEMENT_TYPES = ["BALANCE_SHEET", "PROFIT_AND_LOSS", "CASH_FLOW"] as const;
25
+
26
+ const BALANCE_SHEET_CLASSIFICATIONS = ["ASSET", "LIABILITY", "EQUITY", "RETAINED_EARNINGS"];
27
+ const PROFIT_AND_LOSS_CLASSIFICATIONS = ["REVENUE", "EXPENSE"];
28
+ const CASH_FLOW_CLASSIFICATIONS = ["ASSET", "LIABILITY", "REVENUE", "EXPENSE"];
29
+
30
+ function getClassificationsForType(statementType: string): string[] {
31
+ switch (statementType) {
32
+ case "BALANCE_SHEET":
33
+ return BALANCE_SHEET_CLASSIFICATIONS;
34
+ case "PROFIT_AND_LOSS":
35
+ return PROFIT_AND_LOSS_CLASSIFICATIONS;
36
+ case "CASH_FLOW":
37
+ return CASH_FLOW_CLASSIFICATIONS;
38
+ default:
39
+ return [];
40
+ }
41
+ }
42
+
43
+ function getSectionType(classification: string, statementType: string): string {
44
+ if (statementType === "BALANCE_SHEET") {
45
+ if (classification === "ASSET") return "Assets";
46
+ if (classification === "LIABILITY") return "Liabilities";
47
+ return "Equity";
48
+ }
49
+ if (statementType === "PROFIT_AND_LOSS") {
50
+ if (classification === "REVENUE") return "Revenue";
51
+ return "Expenses";
52
+ }
53
+ // CASH_FLOW
54
+ if (classification === "REVENUE" || classification === "EXPENSE") return "Operating Activities";
55
+ if (classification === "ASSET") return "Investing Activities";
56
+ return "Financing Activities";
57
+ }
58
+
59
+ interface AuditEntry {
60
+ type: string;
61
+ statementType?: string;
62
+ actorId?: string;
63
+ }
64
+
65
+ export async function run(
66
+ db: Transaction,
67
+ input: GenerateFinancialStatementInput,
68
+ ctx: CommandContext,
69
+ ) {
70
+ const auditTrail: AuditEntry[] = [];
71
+
72
+ // 1. Validate company exists and is ACTIVE
73
+ const company = await db
74
+ .selectFrom("Company" as never)
75
+ .where("id" as never, "=", input.companyId as never)
76
+ .selectAll()
77
+ .executeTakeFirst();
78
+
79
+ if (!company || (company as Record<string, unknown>).status !== "ACTIVE") {
80
+ return err(new CompanyNotFoundError(input.companyId));
81
+ }
82
+
83
+ // 2. Validate CoA exists and is ACTIVE
84
+ const coa = await db
85
+ .selectFrom("ChartOfAccounts" as never)
86
+ .where("id" as never, "=", input.chartOfAccountsId as never)
87
+ .selectAll()
88
+ .executeTakeFirst();
89
+
90
+ if (!coa || (coa as Record<string, unknown>).status !== "ACTIVE") {
91
+ return err(new ChartOfAccountsNotFoundError(input.chartOfAccountsId));
92
+ }
93
+
94
+ // 3. Validate statementType is valid
95
+ if (
96
+ !VALID_STATEMENT_TYPES.includes(input.statementType as (typeof VALID_STATEMENT_TYPES)[number])
97
+ ) {
98
+ return err(new InvalidStatementTypeError(input.statementType));
99
+ }
100
+
101
+ // 4. Validate reporting parameters
102
+ if (input.statementType === "BALANCE_SHEET") {
103
+ if (!input.reportingDate) {
104
+ return err(new InvalidReportingParametersError(input.statementType));
105
+ }
106
+ } else {
107
+ // PROFIT_AND_LOSS and CASH_FLOW need startDate + endDate
108
+ if (!input.startDate || !input.endDate) {
109
+ return err(new InvalidReportingParametersError(input.statementType));
110
+ }
111
+ if (input.statementType === "CASH_FLOW" && !input.cashFlowMethod) {
112
+ return err(new InvalidReportingParametersError(input.statementType));
113
+ }
114
+ }
115
+
116
+ // 5. Validate trial balance exists
117
+ const trialBalance = await db
118
+ .selectFrom("TrialBalance" as never)
119
+ .where("id" as never, "=", input.trialBalanceId as never)
120
+ .selectAll()
121
+ .executeTakeFirst();
122
+
123
+ if (!trialBalance) {
124
+ return err(new NoTrialBalanceDataError(input.trialBalanceId));
125
+ }
126
+
127
+ // 6. If comparativePeriodTrialBalanceId, validate it exists
128
+ if (input.comparativePeriodTrialBalanceId) {
129
+ const comparativeTb = await db
130
+ .selectFrom("TrialBalance" as never)
131
+ .where("id" as never, "=", input.comparativePeriodTrialBalanceId as never)
132
+ .selectAll()
133
+ .executeTakeFirst();
134
+
135
+ if (!comparativeTb) {
136
+ return err(new ComparativeDataUnavailableError(input.comparativePeriodTrialBalanceId));
137
+ }
138
+ }
139
+
140
+ // 7. Fetch trial balance lines
141
+ const trialBalanceLines = (await db
142
+ .selectFrom("TrialBalanceLine" as never)
143
+ .where("trialBalanceId" as never, "=", input.trialBalanceId as never)
144
+ .selectAll()
145
+ .execute()) as Record<string, unknown>[];
146
+
147
+ if (trialBalanceLines.length === 0) {
148
+ return err(new NoTrialBalanceDataError(input.trialBalanceId));
149
+ }
150
+
151
+ // Fetch comparative lines if applicable
152
+ let comparativeLines: Record<string, unknown>[] = [];
153
+ if (input.comparativePeriodTrialBalanceId) {
154
+ comparativeLines = (await db
155
+ .selectFrom("TrialBalanceLine" as never)
156
+ .where("trialBalanceId" as never, "=", input.comparativePeriodTrialBalanceId as never)
157
+ .selectAll()
158
+ .execute()) as Record<string, unknown>[];
159
+ }
160
+
161
+ // Build a map of comparative amounts by accountId
162
+ const comparativeMap = new Map<string, number>();
163
+ for (const line of comparativeLines) {
164
+ comparativeMap.set(line.accountId as string, line.closingBalance as number);
165
+ }
166
+
167
+ // 8. Fetch accounts to get classification info
168
+ const classifications = getClassificationsForType(input.statementType);
169
+
170
+ // Build line items from trial balance lines, filtering by account classification
171
+ const now = new Date();
172
+ const lineItems: Record<string, unknown>[] = [];
173
+ let sortOrder = 0;
174
+
175
+ for (const tbLine of trialBalanceLines) {
176
+ // Look up the account to check classification
177
+ const account = await db
178
+ .selectFrom("Account" as never)
179
+ .where("id" as never, "=", tbLine.accountId as never)
180
+ .selectAll()
181
+ .executeTakeFirst();
182
+
183
+ if (!account) continue;
184
+ const acct = account as Record<string, unknown>;
185
+ if (!classifications.includes(acct.classification as string)) continue;
186
+
187
+ sortOrder++;
188
+ lineItems.push({
189
+ accountId: tbLine.accountId,
190
+ accountGroupId: tbLine.accountGroupId ?? null,
191
+ label: tbLine.accountName as string,
192
+ amount: tbLine.closingBalance as number,
193
+ comparativeAmount: comparativeMap.get(tbLine.accountId as string) ?? null,
194
+ lineType: "DETAIL",
195
+ sectionType: tbLine.accountGroupId
196
+ ? getSectionType(acct.classification as string, input.statementType)
197
+ : "Unclassified",
198
+ sortOrder,
199
+ });
200
+ }
201
+
202
+ // Add SUBTOTAL lines for each section
203
+ const sectionTotals = new Map<string, number>();
204
+ for (const item of lineItems) {
205
+ const current = sectionTotals.get(item.sectionType as string) ?? 0;
206
+ sectionTotals.set(item.sectionType as string, current + (item.amount as number));
207
+ }
208
+
209
+ for (const [section, total] of sectionTotals) {
210
+ sortOrder++;
211
+ lineItems.push({
212
+ accountId: null,
213
+ accountGroupId: null,
214
+ label: `Total ${section}`,
215
+ amount: total,
216
+ comparativeAmount: null,
217
+ lineType: "SUBTOTAL",
218
+ sectionType: section,
219
+ sortOrder,
220
+ });
221
+ }
222
+
223
+ // 9. Insert FinancialStatement (DRAFT)
224
+ const financialStatement = await db
225
+ .insertInto("FinancialStatement")
226
+ .values({
227
+ companyId: input.companyId,
228
+ chartOfAccountsId: input.chartOfAccountsId,
229
+ trialBalanceId: input.trialBalanceId,
230
+ comparativePeriodTrialBalanceId: input.comparativePeriodTrialBalanceId ?? null,
231
+ statementType: input.statementType as never,
232
+ status: "DRAFT",
233
+ reportingDate: input.reportingDate ?? null,
234
+ startDate: input.startDate ?? null,
235
+ endDate: input.endDate ?? null,
236
+ cashFlowMethod: input.cashFlowMethod ?? null,
237
+ generatedAt: now,
238
+ finalizedAt: null,
239
+ createdAt: now,
240
+ updatedAt: null,
241
+ })
242
+ .returningAll()
243
+ .executeTakeFirst();
244
+
245
+ // 10. Insert FinancialStatementLineItems
246
+ for (const item of lineItems) {
247
+ await db
248
+ .insertInto("FinancialStatementLineItem")
249
+ .values({
250
+ financialStatementId: financialStatement!.id,
251
+ accountId: item.accountId as string,
252
+ accountGroupId: item.accountGroupId as string | null,
253
+ label: item.label as string,
254
+ amount: item.amount as number,
255
+ comparativeAmount: item.comparativeAmount as number | null,
256
+ lineType: item.lineType as never,
257
+ sectionType: item.sectionType as string,
258
+ sortOrder: item.sortOrder as number,
259
+ createdAt: now,
260
+ updatedAt: null,
261
+ })
262
+ .returningAll()
263
+ .executeTakeFirst();
264
+ }
265
+
266
+ // Record audit event
267
+ auditTrail.push({
268
+ type: "FINANCIAL_STATEMENT_GENERATED",
269
+ statementType: input.statementType,
270
+ actorId: ctx.actorId,
271
+ });
272
+
273
+ // 11. Return financialStatement
274
+ return ok({ financialStatement: financialStatement!, auditTrail });
275
+ }
@@ -0,0 +1,6 @@
1
+ // @generated — do not edit
2
+ import { defineCommand } from "@tailor-platform/erp-kit/module";
3
+ import { permissions } from "../lib/permissions.generated";
4
+ import { run } from "./generatePreliminaryStatements";
5
+
6
+ export const generatePreliminaryStatements = defineCommand(permissions.generatePreliminaryStatements, run);