@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,201 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ PeriodCloseNotFoundError,
6
+ InvalidStatusTransitionError,
7
+ PendingSubledgerTransactionsError,
8
+ } from "../lib/errors.generated";
9
+ import {
10
+ basePeriodClose,
11
+ inProgressPeriodClose,
12
+ subledgersVerifiedPeriodClose,
13
+ baseJournalEntry,
14
+ baseAccountingPeriod,
15
+ } from "../testing/fixtures";
16
+ import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
17
+ import { run } from "./verifySubledgerTransfers";
18
+
19
+ describe("verifySubledgerTransfers", () => {
20
+ it("returns error when PeriodClose record does not exist", async () => {
21
+ const { db, spies } = createMockDb<Transaction>();
22
+ spies.select.mockReturnValueOnce(undefined); // PeriodClose lookup
23
+
24
+ const result = await run(db, { id: "nonexistent" }, commandCtx);
25
+
26
+ expectErr(result, PeriodCloseNotFoundError);
27
+ });
28
+
29
+ it("returns error when PeriodClose is in NOT_STARTED status", async () => {
30
+ const { db, spies } = createMockDb<Transaction>();
31
+ spies.select.mockReturnValueOnce(basePeriodClose); // PeriodClose in NOT_STARTED
32
+
33
+ const result = await run(db, { id: basePeriodClose.id }, commandCtx);
34
+
35
+ expectErr(result, InvalidStatusTransitionError);
36
+ });
37
+
38
+ it("returns error when PeriodClose is already in SUBLEDGERS_VERIFIED status", async () => {
39
+ const { db, spies } = createMockDb<Transaction>();
40
+ spies.select.mockReturnValueOnce(subledgersVerifiedPeriodClose); // PeriodClose in SUBLEDGERS_VERIFIED
41
+
42
+ const result = await run(db, { id: subledgersVerifiedPeriodClose.id }, commandCtx);
43
+
44
+ expectErr(result, InvalidStatusTransitionError);
45
+ });
46
+
47
+ it("returns error when purchase module has pending unposted transactions", async () => {
48
+ const { db, spies } = createMockDb<Transaction>();
49
+ const purchaseDraft = {
50
+ ...baseJournalEntry,
51
+ id: "je-purchase-draft",
52
+ journalType: "PURCHASE",
53
+ accountingPeriodId: baseAccountingPeriod.id,
54
+ status: "DRAFT",
55
+ };
56
+ spies.select
57
+ .mockReturnValueOnce(inProgressPeriodClose) // PeriodClose lookup
58
+ .mockReturnValueOnce([purchaseDraft]) // purchase DRAFT entries
59
+ .mockReturnValueOnce([]) // sales: no pending
60
+ .mockReturnValueOnce([]) // inventory: no pending
61
+ .mockReturnValueOnce([]); // manufacturing: no pending
62
+
63
+ const result = await run(db, { id: inProgressPeriodClose.id }, commandCtx);
64
+
65
+ expectErr(result, PendingSubledgerTransactionsError);
66
+ });
67
+
68
+ it("returns error when sales module has pending unposted transactions", async () => {
69
+ const { db, spies } = createMockDb<Transaction>();
70
+ const salesDraft = {
71
+ ...baseJournalEntry,
72
+ id: "je-sales-draft",
73
+ journalType: "SALES",
74
+ accountingPeriodId: baseAccountingPeriod.id,
75
+ status: "DRAFT",
76
+ };
77
+ spies.select
78
+ .mockReturnValueOnce(inProgressPeriodClose) // PeriodClose lookup
79
+ .mockReturnValueOnce([]) // purchase: no pending
80
+ .mockReturnValueOnce([salesDraft]) // sales: pending
81
+ .mockReturnValueOnce([]) // inventory: no pending
82
+ .mockReturnValueOnce([]); // manufacturing: no pending
83
+
84
+ const result = await run(db, { id: inProgressPeriodClose.id }, commandCtx);
85
+
86
+ expectErr(result, PendingSubledgerTransactionsError);
87
+ });
88
+
89
+ it("returns error when inventory module has pending unposted transactions", async () => {
90
+ const { db, spies } = createMockDb<Transaction>();
91
+ const inventoryDraft = {
92
+ ...baseJournalEntry,
93
+ id: "je-inventory-draft",
94
+ journalType: "MISCELLANEOUS",
95
+ accountingPeriodId: baseAccountingPeriod.id,
96
+ status: "DRAFT",
97
+ };
98
+ spies.select
99
+ .mockReturnValueOnce(inProgressPeriodClose) // PeriodClose lookup
100
+ .mockReturnValueOnce([]) // purchase: no pending
101
+ .mockReturnValueOnce([]) // sales: no pending
102
+ .mockReturnValueOnce([inventoryDraft]) // inventory: pending
103
+ .mockReturnValueOnce([]); // manufacturing: no pending
104
+
105
+ const result = await run(db, { id: inProgressPeriodClose.id }, commandCtx);
106
+
107
+ expectErr(result, PendingSubledgerTransactionsError);
108
+ });
109
+
110
+ it("returns error when manufacturing module has pending unposted transactions", async () => {
111
+ const { db, spies } = createMockDb<Transaction>();
112
+ const manufacturingDraft = {
113
+ ...baseJournalEntry,
114
+ id: "je-manufacturing-draft",
115
+ journalType: "MISCELLANEOUS",
116
+ accountingPeriodId: baseAccountingPeriod.id,
117
+ status: "DRAFT",
118
+ };
119
+ spies.select
120
+ .mockReturnValueOnce(inProgressPeriodClose) // PeriodClose lookup
121
+ .mockReturnValueOnce([]) // purchase: no pending
122
+ .mockReturnValueOnce([]) // sales: no pending
123
+ .mockReturnValueOnce([]) // inventory: no pending
124
+ .mockReturnValueOnce([manufacturingDraft]); // manufacturing: pending
125
+
126
+ const result = await run(db, { id: inProgressPeriodClose.id }, commandCtx);
127
+
128
+ expectErr(result, PendingSubledgerTransactionsError);
129
+ });
130
+
131
+ it("transitions IN_PROGRESS to SUBLEDGERS_VERIFIED when all subledgers are reconciled", async () => {
132
+ const { db, spies } = createMockDb<Transaction>();
133
+ const updatedPeriodClose = {
134
+ ...inProgressPeriodClose,
135
+ status: "SUBLEDGERS_VERIFIED",
136
+ completionPercentage: 25,
137
+ };
138
+ spies.select
139
+ .mockReturnValueOnce(inProgressPeriodClose) // PeriodClose lookup
140
+ .mockReturnValueOnce([]) // purchase: no pending
141
+ .mockReturnValueOnce([]) // sales: no pending
142
+ .mockReturnValueOnce([]) // inventory: no pending
143
+ .mockReturnValueOnce([]); // manufacturing: no pending
144
+ spies.update.mockReturnValueOnce(updatedPeriodClose);
145
+
146
+ const result = await run(db, { id: inProgressPeriodClose.id }, commandCtx);
147
+
148
+ const value = expectOk(result);
149
+ expect(value.periodClose.status).toBe("SUBLEDGERS_VERIFIED");
150
+ });
151
+
152
+ it("updates completionPercentage after successful verification", async () => {
153
+ const { db, spies } = createMockDb<Transaction>();
154
+ const updatedPeriodClose = {
155
+ ...inProgressPeriodClose,
156
+ status: "SUBLEDGERS_VERIFIED",
157
+ completionPercentage: 25,
158
+ };
159
+ spies.select
160
+ .mockReturnValueOnce(inProgressPeriodClose) // PeriodClose lookup
161
+ .mockReturnValueOnce([]) // purchase: no pending
162
+ .mockReturnValueOnce([]) // sales: no pending
163
+ .mockReturnValueOnce([]) // inventory: no pending
164
+ .mockReturnValueOnce([]); // manufacturing: no pending
165
+ spies.update.mockReturnValueOnce(updatedPeriodClose);
166
+
167
+ const result = await run(db, { id: inProgressPeriodClose.id }, commandCtx);
168
+
169
+ const value = expectOk(result);
170
+ expect(value.periodClose.completionPercentage).toBe(25);
171
+ });
172
+
173
+ it("emits audit event recording subledger verification results and status transition", async () => {
174
+ const { db, spies } = createMockDb<Transaction>();
175
+ const updatedPeriodClose = {
176
+ ...inProgressPeriodClose,
177
+ status: "SUBLEDGERS_VERIFIED",
178
+ completionPercentage: 25,
179
+ };
180
+ spies.select
181
+ .mockReturnValueOnce(inProgressPeriodClose) // PeriodClose lookup
182
+ .mockReturnValueOnce([]) // purchase: no pending
183
+ .mockReturnValueOnce([]) // sales: no pending
184
+ .mockReturnValueOnce([]) // inventory: no pending
185
+ .mockReturnValueOnce([]); // manufacturing: no pending
186
+ spies.update.mockReturnValueOnce(updatedPeriodClose);
187
+
188
+ const result = await run(db, { id: inProgressPeriodClose.id }, commandCtx);
189
+
190
+ const value = expectOk(result);
191
+ expect(value.auditEvent).toBeDefined();
192
+ expect(value.auditEvent.type).toBe("SUBLEDGER_VERIFICATION_COMPLETED");
193
+ expect(value.auditEvent.actorId).toBe(commandCtx.actorId);
194
+ expect(value.auditEvent.from).toBe("IN_PROGRESS");
195
+ expect(value.auditEvent.to).toBe("SUBLEDGERS_VERIFIED");
196
+ expect(value.auditEvent.verificationResults).toHaveLength(4);
197
+ expect(
198
+ value.auditEvent.verificationResults.every((r: { reconciled: boolean }) => r.reconciled),
199
+ ).toBe(true);
200
+ });
201
+ });
@@ -0,0 +1,113 @@
1
+ import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";
2
+ import type { Transaction } from "../generated/kysely-tailordb";
3
+ import {
4
+ PeriodCloseNotFoundError,
5
+ InvalidStatusTransitionError,
6
+ PendingSubledgerTransactionsError,
7
+ } from "../lib/errors.generated";
8
+
9
+ export interface VerifySubledgerTransfersInput {
10
+ id: string;
11
+ }
12
+
13
+ interface SubledgerVerificationResult {
14
+ module: string;
15
+ journalType: string;
16
+ pendingCount: number;
17
+ reconciled: boolean;
18
+ }
19
+
20
+ const SUBLEDGER_MODULES: { module: string; journalType: string }[] = [
21
+ { module: "purchase", journalType: "PURCHASE" },
22
+ { module: "sales", journalType: "SALES" },
23
+ { module: "inventory", journalType: "MISCELLANEOUS" },
24
+ { module: "manufacturing", journalType: "MISCELLANEOUS" },
25
+ ];
26
+
27
+ const SUBLEDGERS_VERIFIED_COMPLETION_PERCENTAGE = 25;
28
+
29
+ /**
30
+ * Function: verifySubledgerTransfers
31
+ *
32
+ * Checks that all registered subledger modules have completed their
33
+ * transaction transfers to the general ledger for the closing period.
34
+ * If all subledgers are reconciled, the PeriodClose transitions from
35
+ * IN_PROGRESS to SUBLEDGERS_VERIFIED.
36
+ */
37
+ export async function run(
38
+ db: Transaction,
39
+ input: VerifySubledgerTransfersInput,
40
+ ctx: CommandContext,
41
+ ) {
42
+ const { id } = input;
43
+
44
+ // 1. Find PeriodClose record
45
+ const periodClose = await db
46
+ .selectFrom("PeriodClose")
47
+ .selectAll()
48
+ .where("id", "=", id)
49
+ .forUpdate()
50
+ .executeTakeFirst();
51
+
52
+ if (!periodClose) {
53
+ return err(new PeriodCloseNotFoundError(id));
54
+ }
55
+
56
+ // 2. Validate PeriodClose is in IN_PROGRESS status
57
+ if (periodClose.status !== "IN_PROGRESS") {
58
+ return err(new InvalidStatusTransitionError(id));
59
+ }
60
+
61
+ // 3. Check all registered subledger modules for pending unposted transactions
62
+ const verificationResults: SubledgerVerificationResult[] = [];
63
+
64
+ for (const subledger of SUBLEDGER_MODULES) {
65
+ const pendingEntries = await db
66
+ .selectFrom("JournalEntry")
67
+ .selectAll()
68
+ .where("accountingPeriodId", "=", periodClose.accountingPeriodId)
69
+ .where("journalType", "=", subledger.journalType as "PURCHASE" | "SALES" | "MISCELLANEOUS")
70
+ .where("status", "=", "DRAFT")
71
+ .execute();
72
+
73
+ verificationResults.push({
74
+ module: subledger.module,
75
+ journalType: subledger.journalType,
76
+ pendingCount: pendingEntries.length,
77
+ reconciled: pendingEntries.length === 0,
78
+ });
79
+ }
80
+
81
+ // 4. If any subledger has pending transactions, fail
82
+ const pendingModules = verificationResults.filter((r) => !r.reconciled);
83
+ if (pendingModules.length > 0) {
84
+ return err(new PendingSubledgerTransactionsError(id));
85
+ }
86
+
87
+ // 5. Transition PeriodClose to SUBLEDGERS_VERIFIED and update completionPercentage
88
+ const now = new Date();
89
+ const updatedPeriodClose = await db
90
+ .updateTable("PeriodClose")
91
+ .set({
92
+ status: "SUBLEDGERS_VERIFIED",
93
+ completionPercentage: SUBLEDGERS_VERIFIED_COMPLETION_PERCENTAGE,
94
+ subledgerVerificationDetails: JSON.stringify(verificationResults),
95
+ updatedAt: now,
96
+ })
97
+ .where("id", "=", id)
98
+ .returningAll()
99
+ .executeTakeFirst();
100
+
101
+ // 6. Emit audit event
102
+ const auditEvent = {
103
+ type: "SUBLEDGER_VERIFICATION_COMPLETED",
104
+ actorId: ctx.actorId,
105
+ timestamp: now,
106
+ periodCloseId: id,
107
+ from: "IN_PROGRESS",
108
+ to: "SUBLEDGERS_VERIFIED",
109
+ verificationResults,
110
+ };
111
+
112
+ return ok({ periodClose: updatedPeriodClose!, auditEvent });
113
+ }
@@ -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 "./verifyTrialBalance";
5
+
6
+ export const verifyTrialBalance = defineCommand(permissions.verifyTrialBalance, run);
@@ -0,0 +1,136 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ PeriodCloseNotFoundError,
6
+ InvalidStatusTransitionError,
7
+ TrialBalanceImbalancedError,
8
+ } from "../lib/errors.generated";
9
+ import {
10
+ adjustmentsPostedPeriodClose,
11
+ subledgersVerifiedPeriodClose,
12
+ trialBalanceVerifiedPeriodClose,
13
+ baseTrialBalance,
14
+ baseAccountingPeriod,
15
+ baseChartOfAccounts,
16
+ } from "../testing/fixtures";
17
+ import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
18
+ import { run } from "./verifyTrialBalance";
19
+
20
+ describe("verifyTrialBalance", () => {
21
+ it("returns error when PeriodClose record does not exist", async () => {
22
+ const { db, spies } = createMockDb<Transaction>();
23
+ spies.select.mockReturnValueOnce(undefined); // PeriodClose lookup
24
+
25
+ const result = await run(db, { id: "nonexistent" }, commandCtx);
26
+
27
+ expectErr(result, PeriodCloseNotFoundError);
28
+ });
29
+
30
+ it("returns error when PeriodClose is in SUBLEDGERS_VERIFIED status", async () => {
31
+ const { db, spies } = createMockDb<Transaction>();
32
+ spies.select.mockReturnValueOnce(subledgersVerifiedPeriodClose); // PeriodClose lookup
33
+
34
+ const result = await run(db, { id: subledgersVerifiedPeriodClose.id }, commandCtx);
35
+
36
+ expectErr(result, InvalidStatusTransitionError);
37
+ });
38
+
39
+ it("returns error when PeriodClose is already in TRIAL_BALANCE_VERIFIED status", async () => {
40
+ const { db, spies } = createMockDb<Transaction>();
41
+ spies.select.mockReturnValueOnce(trialBalanceVerifiedPeriodClose); // PeriodClose lookup
42
+
43
+ const result = await run(db, { id: trialBalanceVerifiedPeriodClose.id }, commandCtx);
44
+
45
+ expectErr(result, InvalidStatusTransitionError);
46
+ });
47
+
48
+ it("returns error when trial balance has a non-zero debit-credit discrepancy", async () => {
49
+ const { db, spies } = createMockDb<Transaction>();
50
+ const imbalancedTrialBalance = {
51
+ ...baseTrialBalance,
52
+ id: "trial-balance-imbalanced",
53
+ totalDebits: 10000,
54
+ totalCredits: 9500,
55
+ isBalanced: false,
56
+ };
57
+ spies.select
58
+ .mockReturnValueOnce(adjustmentsPostedPeriodClose) // PeriodClose lookup
59
+ .mockReturnValueOnce(baseAccountingPeriod) // AccountingPeriod lookup
60
+ .mockReturnValueOnce(baseChartOfAccounts) // ChartOfAccounts lookup
61
+ .mockReturnValueOnce(imbalancedTrialBalance); // TrialBalance lookup
62
+
63
+ const result = await run(db, { id: adjustmentsPostedPeriodClose.id }, commandCtx);
64
+
65
+ expectErr(result, TrialBalanceImbalancedError);
66
+ });
67
+
68
+ it("transitions ADJUSTMENTS_POSTED to TRIAL_BALANCE_VERIFIED when trial balance is balanced", async () => {
69
+ const { db, spies } = createMockDb<Transaction>();
70
+ const updatedPeriodClose = {
71
+ ...adjustmentsPostedPeriodClose,
72
+ status: "TRIAL_BALANCE_VERIFIED",
73
+ trialBalanceId: baseTrialBalance.id,
74
+ completionPercentage: 62,
75
+ };
76
+ spies.select
77
+ .mockReturnValueOnce(adjustmentsPostedPeriodClose) // PeriodClose lookup
78
+ .mockReturnValueOnce(baseAccountingPeriod) // AccountingPeriod lookup
79
+ .mockReturnValueOnce(baseChartOfAccounts) // ChartOfAccounts lookup
80
+ .mockReturnValueOnce(baseTrialBalance); // TrialBalance lookup (balanced)
81
+ spies.update.mockReturnValueOnce(updatedPeriodClose);
82
+
83
+ const result = await run(db, { id: adjustmentsPostedPeriodClose.id }, commandCtx);
84
+
85
+ const value = expectOk(result);
86
+ expect(value.periodClose.status).toBe("TRIAL_BALANCE_VERIFIED");
87
+ });
88
+
89
+ it("updates completionPercentage after successful verification", async () => {
90
+ const { db, spies } = createMockDb<Transaction>();
91
+ const updatedPeriodClose = {
92
+ ...adjustmentsPostedPeriodClose,
93
+ status: "TRIAL_BALANCE_VERIFIED",
94
+ trialBalanceId: baseTrialBalance.id,
95
+ completionPercentage: 62,
96
+ };
97
+ spies.select
98
+ .mockReturnValueOnce(adjustmentsPostedPeriodClose) // PeriodClose lookup
99
+ .mockReturnValueOnce(baseAccountingPeriod) // AccountingPeriod lookup
100
+ .mockReturnValueOnce(baseChartOfAccounts) // ChartOfAccounts lookup
101
+ .mockReturnValueOnce(baseTrialBalance); // TrialBalance lookup (balanced)
102
+ spies.update.mockReturnValueOnce(updatedPeriodClose);
103
+
104
+ const result = await run(db, { id: adjustmentsPostedPeriodClose.id }, commandCtx);
105
+
106
+ const value = expectOk(result);
107
+ expect(value.periodClose.completionPercentage).toBe(62);
108
+ });
109
+
110
+ it("emits audit event recording trial balance result and status transition", async () => {
111
+ const { db, spies } = createMockDb<Transaction>();
112
+ const updatedPeriodClose = {
113
+ ...adjustmentsPostedPeriodClose,
114
+ status: "TRIAL_BALANCE_VERIFIED",
115
+ trialBalanceId: baseTrialBalance.id,
116
+ completionPercentage: 62,
117
+ };
118
+ spies.select
119
+ .mockReturnValueOnce(adjustmentsPostedPeriodClose) // PeriodClose lookup
120
+ .mockReturnValueOnce(baseAccountingPeriod) // AccountingPeriod lookup
121
+ .mockReturnValueOnce(baseChartOfAccounts) // ChartOfAccounts lookup
122
+ .mockReturnValueOnce(baseTrialBalance); // TrialBalance lookup (balanced)
123
+ spies.update.mockReturnValueOnce(updatedPeriodClose);
124
+
125
+ const result = await run(db, { id: adjustmentsPostedPeriodClose.id }, commandCtx);
126
+
127
+ const value = expectOk(result);
128
+ expect(value.auditEvent).toBeDefined();
129
+ expect(value.auditEvent.actorId).toBe(commandCtx.actorId);
130
+ expect(value.auditEvent.timestamp).toBeInstanceOf(Date);
131
+ expect(value.auditEvent.from).toBe("ADJUSTMENTS_POSTED");
132
+ expect(value.auditEvent.to).toBe("TRIAL_BALANCE_VERIFIED");
133
+ expect(value.auditEvent.trialBalanceId).toBe(baseTrialBalance.id);
134
+ expect(value.auditEvent.isBalanced).toBe(true);
135
+ });
136
+ });
@@ -0,0 +1,97 @@
1
+ import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";
2
+ import type { Transaction } from "../generated/kysely-tailordb";
3
+ import {
4
+ PeriodCloseNotFoundError,
5
+ InvalidStatusTransitionError,
6
+ TrialBalanceImbalancedError,
7
+ } from "../lib/errors.generated";
8
+
9
+ export interface VerifyTrialBalanceInput {
10
+ id: string;
11
+ }
12
+
13
+ /**
14
+ * Function: verifyTrialBalance
15
+ *
16
+ * Checks that the period's trial balance is balanced (total debits equal total
17
+ * credits across all accounts) and transitions the PeriodClose from
18
+ * ADJUSTMENTS_POSTED to TRIAL_BALANCE_VERIFIED status.
19
+ */
20
+ export async function run(db: Transaction, input: VerifyTrialBalanceInput, ctx: CommandContext) {
21
+ const { id } = input;
22
+
23
+ // 1. Find PeriodClose record
24
+ const periodClose = await db
25
+ .selectFrom("PeriodClose")
26
+ .selectAll()
27
+ .where("id", "=", id)
28
+ .forUpdate()
29
+ .executeTakeFirst();
30
+
31
+ if (!periodClose) {
32
+ return err(new PeriodCloseNotFoundError(id));
33
+ }
34
+
35
+ // 2. Validate status is ADJUSTMENTS_POSTED
36
+ if (periodClose.status !== "ADJUSTMENTS_POSTED") {
37
+ return err(new InvalidStatusTransitionError(id));
38
+ }
39
+
40
+ // 3. Retrieve the accounting period to find the company and period context
41
+ const accountingPeriod = await db
42
+ .selectFrom("AccountingPeriod")
43
+ .selectAll()
44
+ .where("id", "=", periodClose.accountingPeriodId)
45
+ .executeTakeFirst();
46
+
47
+ // 4. Retrieve the active chart of accounts for trial balance generation
48
+ const chartOfAccounts = await db
49
+ .selectFrom("ChartOfAccounts")
50
+ .selectAll()
51
+ .where("companyId", "=", accountingPeriod!.companyId)
52
+ .where("status", "=", "ACTIVE")
53
+ .executeTakeFirst();
54
+
55
+ // 5. Generate or retrieve the trial balance for the period
56
+ const trialBalance = await db
57
+ .selectFrom("TrialBalance")
58
+ .selectAll()
59
+ .where("accountingPeriodId", "=", periodClose.accountingPeriodId)
60
+ .where("chartOfAccountsId", "=", chartOfAccounts!.id)
61
+ .executeTakeFirst();
62
+
63
+ // 6. Verify trial balance is balanced
64
+ if (!trialBalance || trialBalance.totalDebits !== trialBalance.totalCredits) {
65
+ const discrepancy = trialBalance
66
+ ? Math.abs(trialBalance.totalDebits - trialBalance.totalCredits)
67
+ : 0;
68
+ return err(new TrialBalanceImbalancedError(`${id} (discrepancy: ${discrepancy})`));
69
+ }
70
+
71
+ // 7. Transition PeriodClose to TRIAL_BALANCE_VERIFIED and update completionPercentage
72
+ const now = new Date();
73
+ const updated = await db
74
+ .updateTable("PeriodClose")
75
+ .set({
76
+ status: "TRIAL_BALANCE_VERIFIED",
77
+ trialBalanceId: trialBalance.id,
78
+ completionPercentage: 62,
79
+ updatedAt: now,
80
+ })
81
+ .where("id", "=", id)
82
+ .returningAll()
83
+ .executeTakeFirstOrThrow();
84
+
85
+ // 8. Emit audit event
86
+ const auditEvent = {
87
+ type: "TRIAL_BALANCE_VERIFIED",
88
+ from: "ADJUSTMENTS_POSTED",
89
+ to: "TRIAL_BALANCE_VERIFIED",
90
+ actorId: ctx.actorId,
91
+ timestamp: now,
92
+ trialBalanceId: trialBalance.id,
93
+ isBalanced: true,
94
+ };
95
+
96
+ return ok({ periodClose: updated, auditEvent });
97
+ }
File without changes
@@ -0,0 +1,58 @@
1
+ import {
2
+ db,
3
+ type TailorAnyDBField,
4
+ type TailorAnyDBType,
5
+ unsafeAllowAllGqlPermission,
6
+ unsafeAllowAllTypePermission,
7
+ } from "@tailor-platform/sdk";
8
+ import { company as companyStub } from "../lib/_db_deps";
9
+ import { fiscalYear } from "./fiscalYear";
10
+
11
+ export const ACCOUNTING_PERIOD_STATUSES: [string, string, string, string, string] = [
12
+ "NEVER_OPENED",
13
+ "FUTURE_ENTERABLE",
14
+ "OPEN",
15
+ "CLOSED",
16
+ "PERMANENTLY_CLOSED",
17
+ ];
18
+
19
+ export interface CreateAccountingPeriodTypeParams<F extends Record<string, TailorAnyDBField>> {
20
+ fields?: F;
21
+ companyType?: TailorAnyDBType;
22
+ fiscalYearType?: TailorAnyDBType;
23
+ }
24
+
25
+ export function createAccountingPeriodType<const F extends Record<string, TailorAnyDBField>>(
26
+ params: CreateAccountingPeriodTypeParams<F>,
27
+ ) {
28
+ return db
29
+ .type("AccountingPeriod", {
30
+ companyId: db
31
+ .uuid()
32
+ .relation({
33
+ type: "n-1",
34
+ toward: { type: params.companyType ?? companyStub },
35
+ backward: "accountingPeriods",
36
+ })
37
+ .description("Foreign key to Company"),
38
+ fiscalYearId: db
39
+ .uuid()
40
+ .relation({
41
+ type: "n-1",
42
+ toward: { type: params.fiscalYearType ?? fiscalYear },
43
+ backward: "accountingPeriods",
44
+ })
45
+ .description("Foreign key to FiscalYear"),
46
+ name: db.string().description("Period name"),
47
+ startDate: db.date().description("Period start date"),
48
+ endDate: db.date().description("Period end date"),
49
+ periodType: db.enum(["OPERATING", "ADJUSTMENT"]).description("Period type"),
50
+ status: db.enum(ACCOUNTING_PERIOD_STATUSES).description("Accounting period lifecycle status"),
51
+ ...((params.fields ?? {}) as F),
52
+ ...db.fields.timestamps(),
53
+ })
54
+ .permission(unsafeAllowAllTypePermission)
55
+ .gqlPermission(unsafeAllowAllGqlPermission);
56
+ }
57
+
58
+ export const accountingPeriod = createAccountingPeriodType({});