@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,257 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ InvalidPeriodStatusError,
6
+ AccountNotActiveError,
7
+ AccountNotFoundError,
8
+ InvalidAmountError,
9
+ CompanyMismatchError,
10
+ } from "../lib/errors.generated";
11
+ import {
12
+ baseAccountingPeriod,
13
+ neverOpenedPeriod,
14
+ closedPeriod,
15
+ baseAccount,
16
+ baseAccount2,
17
+ inactiveAccount,
18
+ baseCompany,
19
+ baseJournalEntry,
20
+ } from "../testing/fixtures";
21
+ import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
22
+ import { run } from "./processSalesHandoff";
23
+
24
+ describe("processSalesHandoff", () => {
25
+ const baseInput = {
26
+ companyId: baseCompany.id,
27
+ accountingPeriodId: baseAccountingPeriod.id,
28
+ sourceDocumentReference: "INV-001",
29
+ entryDate: new Date("2024-01-15"),
30
+ documentType: "INVOICE",
31
+ debitAccountId: baseAccount.id,
32
+ creditAccountId: baseAccount2.id,
33
+ amount: 1000,
34
+ };
35
+
36
+ it("returns existing entry for idempotent duplicate", async () => {
37
+ const { db, spies } = createMockDb<Transaction>();
38
+ const existingEntry = { ...baseJournalEntry, sourceDocumentReference: "INV-001" };
39
+ spies.select.mockReturnValueOnce(existingEntry);
40
+
41
+ const result = await run(db, baseInput, commandCtx);
42
+
43
+ const value = expectOk(result);
44
+ expect(value.journalEntry).toEqual(existingEntry);
45
+ expect(value.idempotent).toBe(true);
46
+ expect(spies.insert).not.toHaveBeenCalled();
47
+ });
48
+
49
+ it("returns error when amount is zero or negative", async () => {
50
+ const { db, spies } = createMockDb<Transaction>();
51
+ spies.select.mockReturnValueOnce(undefined); // no existing entry
52
+
53
+ const result = await run(db, { ...baseInput, amount: 0 }, commandCtx);
54
+
55
+ expectErr(result, InvalidAmountError);
56
+ });
57
+
58
+ it("returns error when amount is negative", async () => {
59
+ const { db, spies } = createMockDb<Transaction>();
60
+ spies.select.mockReturnValueOnce(undefined); // no existing entry
61
+
62
+ const result = await run(db, { ...baseInput, amount: -100 }, commandCtx);
63
+
64
+ expectErr(result, InvalidAmountError);
65
+ });
66
+
67
+ it("returns error when period is not OPEN or FUTURE_ENTERABLE", async () => {
68
+ const { db, spies } = createMockDb<Transaction>();
69
+ spies.select
70
+ .mockReturnValueOnce(undefined) // no existing entry
71
+ .mockReturnValueOnce(neverOpenedPeriod); // period lookup
72
+
73
+ const result = await run(
74
+ db,
75
+ { ...baseInput, accountingPeriodId: neverOpenedPeriod.id },
76
+ commandCtx,
77
+ );
78
+
79
+ expectErr(result, InvalidPeriodStatusError);
80
+ });
81
+
82
+ it("returns error when period is CLOSED", async () => {
83
+ const { db, spies } = createMockDb<Transaction>();
84
+ spies.select
85
+ .mockReturnValueOnce(undefined) // no existing entry
86
+ .mockReturnValueOnce(closedPeriod); // period lookup
87
+
88
+ const result = await run(db, { ...baseInput, accountingPeriodId: closedPeriod.id }, commandCtx);
89
+
90
+ expectErr(result, InvalidPeriodStatusError);
91
+ });
92
+
93
+ it("returns error when company does not match period company", async () => {
94
+ const { db, spies } = createMockDb<Transaction>();
95
+ spies.select
96
+ .mockReturnValueOnce(undefined) // no existing entry
97
+ .mockReturnValueOnce(baseAccountingPeriod); // period lookup
98
+
99
+ const result = await run(db, { ...baseInput, companyId: "other-company" }, commandCtx);
100
+
101
+ expectErr(result, CompanyMismatchError);
102
+ });
103
+
104
+ it("returns error when debit account is not active", async () => {
105
+ const { db, spies } = createMockDb<Transaction>();
106
+ spies.select
107
+ .mockReturnValueOnce(undefined) // no existing entry
108
+ .mockReturnValueOnce(baseAccountingPeriod) // period lookup
109
+ .mockReturnValueOnce(inactiveAccount); // debit account lookup
110
+
111
+ const result = await run(db, { ...baseInput, debitAccountId: inactiveAccount.id }, commandCtx);
112
+
113
+ expectErr(result, AccountNotActiveError);
114
+ });
115
+
116
+ it("returns error when credit account is not active", async () => {
117
+ const { db, spies } = createMockDb<Transaction>();
118
+ spies.select
119
+ .mockReturnValueOnce(undefined) // no existing entry
120
+ .mockReturnValueOnce(baseAccountingPeriod) // period lookup
121
+ .mockReturnValueOnce(baseAccount) // debit account lookup (active)
122
+ .mockReturnValueOnce(inactiveAccount); // credit account lookup
123
+
124
+ const result = await run(db, { ...baseInput, creditAccountId: inactiveAccount.id }, commandCtx);
125
+
126
+ expectErr(result, AccountNotActiveError);
127
+ });
128
+
129
+ it("returns error when debit account does not exist", async () => {
130
+ const { db, spies } = createMockDb<Transaction>();
131
+ spies.select
132
+ .mockReturnValueOnce(undefined) // no existing entry
133
+ .mockReturnValueOnce(baseAccountingPeriod) // period lookup
134
+ .mockReturnValueOnce(undefined); // debit account not found
135
+
136
+ const result = await run(db, baseInput, commandCtx);
137
+
138
+ expectErr(result, AccountNotFoundError);
139
+ });
140
+
141
+ it("returns error when credit account does not exist", async () => {
142
+ const { db, spies } = createMockDb<Transaction>();
143
+ spies.select
144
+ .mockReturnValueOnce(undefined) // no existing entry
145
+ .mockReturnValueOnce(baseAccountingPeriod) // period lookup
146
+ .mockReturnValueOnce(baseAccount) // debit account lookup (active)
147
+ .mockReturnValueOnce(undefined); // credit account not found
148
+
149
+ const result = await run(db, baseInput, commandCtx);
150
+
151
+ expectErr(result, AccountNotFoundError);
152
+ });
153
+
154
+ it("creates journal entry with correct type and amounts", async () => {
155
+ const { db, spies } = createMockDb<Transaction>();
156
+ const createdEntry = {
157
+ ...baseJournalEntry,
158
+ journalType: "SALES",
159
+ status: "POSTED",
160
+ sourceDocumentReference: "INV-001",
161
+ };
162
+ spies.select
163
+ .mockReturnValueOnce(undefined) // no existing entry
164
+ .mockReturnValueOnce(baseAccountingPeriod) // period lookup
165
+ .mockReturnValueOnce(baseAccount) // debit account lookup
166
+ .mockReturnValueOnce(baseAccount2); // credit account lookup
167
+ spies.insert
168
+ .mockReturnValueOnce(createdEntry) // journal entry insert
169
+ .mockReturnValueOnce([]); // journal lines insert
170
+
171
+ const result = await run(db, baseInput, commandCtx);
172
+
173
+ const value = expectOk(result);
174
+ expect(value.journalEntry.journalType).toBe("SALES");
175
+ expect(value.journalEntry.status).toBe("POSTED");
176
+ expect(value.idempotent).toBe(false);
177
+ expect(value.acknowledged).toBe(true);
178
+ });
179
+
180
+ it("handles multi-currency with exchange rate", async () => {
181
+ const { db, spies } = createMockDb<Transaction>();
182
+ const createdEntry = {
183
+ ...baseJournalEntry,
184
+ journalType: "SALES",
185
+ status: "POSTED",
186
+ sourceDocumentReference: "INV-002",
187
+ };
188
+ spies.select
189
+ .mockReturnValueOnce(undefined) // no existing entry
190
+ .mockReturnValueOnce(baseAccountingPeriod) // period lookup
191
+ .mockReturnValueOnce(baseAccount) // debit account lookup
192
+ .mockReturnValueOnce(baseAccount2); // credit account lookup
193
+ spies.insert
194
+ .mockReturnValueOnce(createdEntry) // journal entry insert
195
+ .mockReturnValueOnce([]); // journal lines insert
196
+
197
+ const result = await run(
198
+ db,
199
+ {
200
+ ...baseInput,
201
+ sourceDocumentReference: "INV-002",
202
+ currencyCode: "USD",
203
+ exchangeRate: 1.5,
204
+ amount: 1000,
205
+ },
206
+ commandCtx,
207
+ );
208
+
209
+ const value = expectOk(result);
210
+ expect(value.journalEntry).toBeDefined();
211
+ expect(value.idempotent).toBe(false);
212
+ expect(spies.values).toHaveBeenCalled();
213
+ });
214
+
215
+ it("swaps debit and credit accounts for credit note document type", async () => {
216
+ const { db, spies } = createMockDb<Transaction>();
217
+ const createdEntry = {
218
+ ...baseJournalEntry,
219
+ journalType: "SALES",
220
+ status: "POSTED",
221
+ sourceDocumentReference: "CN-001",
222
+ };
223
+ spies.select
224
+ .mockReturnValueOnce(undefined) // no existing entry
225
+ .mockReturnValueOnce(baseAccountingPeriod) // period lookup
226
+ .mockReturnValueOnce(baseAccount) // debit account lookup
227
+ .mockReturnValueOnce(baseAccount2); // credit account lookup
228
+ spies.insert
229
+ .mockReturnValueOnce(createdEntry) // journal entry insert
230
+ .mockReturnValueOnce([]); // journal lines insert
231
+
232
+ const result = await run(
233
+ db,
234
+ { ...baseInput, sourceDocumentReference: "CN-001", documentType: "CREDIT_NOTE" },
235
+ commandCtx,
236
+ );
237
+
238
+ const value = expectOk(result);
239
+ expect(value.journalEntry.journalType).toBe("SALES");
240
+ expect(value.idempotent).toBe(false);
241
+ // Verify lines were inserted with swapped accounts (credit account becomes debit, debit becomes credit)
242
+ expect(spies.values).toHaveBeenCalledWith(
243
+ expect.arrayContaining([
244
+ expect.objectContaining({
245
+ accountId: baseInput.creditAccountId,
246
+ debitAmount: baseInput.amount,
247
+ creditAmount: null,
248
+ }),
249
+ expect.objectContaining({
250
+ accountId: baseInput.debitAccountId,
251
+ debitAmount: null,
252
+ creditAmount: baseInput.amount,
253
+ }),
254
+ ]),
255
+ );
256
+ });
257
+ });
@@ -0,0 +1,135 @@
1
+ import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";
2
+ import type { Transaction } from "../generated/kysely-tailordb";
3
+ import {
4
+ InvalidPeriodStatusError,
5
+ AccountNotActiveError,
6
+ AccountNotFoundError,
7
+ InvalidAmountError,
8
+ CompanyMismatchError,
9
+ } from "../lib/errors.generated";
10
+
11
+ export interface ProcessSalesHandoffInput {
12
+ companyId: string;
13
+ accountingPeriodId: string;
14
+ sourceDocumentReference: string;
15
+ entryDate: Date;
16
+ documentType: string;
17
+ debitAccountId: string;
18
+ creditAccountId: string;
19
+ amount: number;
20
+ currencyCode?: string;
21
+ exchangeRate?: number;
22
+ description?: string;
23
+ }
24
+
25
+ const VALID_PERIOD_STATUSES = ["OPEN", "FUTURE_ENTERABLE"];
26
+
27
+ export async function run(db: Transaction, input: ProcessSalesHandoffInput, _ctx: CommandContext) {
28
+ // 1. Idempotency check: look for existing entry with same sourceDocumentReference + companyId
29
+ const existing = await db
30
+ .selectFrom("JournalEntry")
31
+ .selectAll()
32
+ .where("sourceDocumentReference", "=", input.sourceDocumentReference)
33
+ .where("companyId", "=", input.companyId)
34
+ .executeTakeFirst();
35
+ if (existing) return ok({ journalEntry: existing, acknowledged: true, idempotent: true });
36
+
37
+ // 2. Validate amount > 0
38
+ if (input.amount <= 0) return err(new InvalidAmountError(input.sourceDocumentReference));
39
+
40
+ // 3. Find and validate period
41
+ const period = await db
42
+ .selectFrom("AccountingPeriod")
43
+ .selectAll()
44
+ .where("id", "=", input.accountingPeriodId)
45
+ .executeTakeFirst();
46
+ if (!period || !VALID_PERIOD_STATUSES.includes(period.status))
47
+ return err(new InvalidPeriodStatusError(input.accountingPeriodId));
48
+
49
+ // 4. Validate company matches period's company
50
+ if (period.companyId !== input.companyId) return err(new CompanyMismatchError(input.companyId));
51
+
52
+ // 5. Validate debit account is ACTIVE
53
+ const debitAccount = await db
54
+ .selectFrom("Account")
55
+ .selectAll()
56
+ .where("id", "=", input.debitAccountId)
57
+ .executeTakeFirst();
58
+ if (!debitAccount) return err(new AccountNotFoundError(input.debitAccountId));
59
+ if (debitAccount.status !== "ACTIVE") return err(new AccountNotActiveError(input.debitAccountId));
60
+
61
+ // 6. Validate credit account is ACTIVE
62
+ const creditAccount = await db
63
+ .selectFrom("Account")
64
+ .selectAll()
65
+ .where("id", "=", input.creditAccountId)
66
+ .executeTakeFirst();
67
+ if (!creditAccount) return err(new AccountNotFoundError(input.creditAccountId));
68
+ if (creditAccount.status !== "ACTIVE")
69
+ return err(new AccountNotActiveError(input.creditAccountId));
70
+
71
+ // 7. Calculate functional amounts
72
+ const rate = input.exchangeRate ?? 1;
73
+ const functionalAmount = input.amount * rate;
74
+
75
+ // 8. Create journal entry (auto-posted)
76
+ const now = new Date();
77
+ const journalEntry = await db
78
+ .insertInto("JournalEntry")
79
+ .values({
80
+ companyId: input.companyId,
81
+ accountingPeriodId: input.accountingPeriodId,
82
+ entryDate: input.entryDate,
83
+ journalType: "SALES",
84
+ referenceNumber: input.sourceDocumentReference,
85
+ status: "POSTED",
86
+ description: input.description ?? null,
87
+ sourceDocumentReference: input.sourceDocumentReference,
88
+ postedAt: now,
89
+ createdAt: now,
90
+ })
91
+ .returningAll()
92
+ .executeTakeFirst();
93
+
94
+ // 9. Create journal lines (debit + credit)
95
+ // For credit notes, swap debit/credit accounts to create a reversing entry
96
+ const isCreditNote = input.documentType === "CREDIT_NOTE";
97
+ const debitLineAccountId = isCreditNote ? input.creditAccountId : input.debitAccountId;
98
+ const creditLineAccountId = isCreditNote ? input.debitAccountId : input.creditAccountId;
99
+
100
+ await db
101
+ .insertInto("JournalLine")
102
+ .values([
103
+ {
104
+ journalEntryId: journalEntry!.id,
105
+ accountId: debitLineAccountId,
106
+ debitAmount: input.amount,
107
+ creditAmount: null,
108
+ functionalDebitAmount: functionalAmount,
109
+ functionalCreditAmount: null,
110
+ currencyCode: input.currencyCode ?? null,
111
+ exchangeRate: input.exchangeRate ?? null,
112
+ createdAt: now,
113
+ },
114
+ {
115
+ journalEntryId: journalEntry!.id,
116
+ accountId: creditLineAccountId,
117
+ debitAmount: null,
118
+ creditAmount: input.amount,
119
+ functionalDebitAmount: null,
120
+ functionalCreditAmount: functionalAmount,
121
+ currencyCode: input.currencyCode ?? null,
122
+ exchangeRate: input.exchangeRate ?? null,
123
+ createdAt: now,
124
+ },
125
+ ])
126
+ .returningAll()
127
+ .execute();
128
+
129
+ return ok({
130
+ journalEntry: journalEntry!,
131
+ acknowledged: true,
132
+ acknowledgedAt: now,
133
+ idempotent: false,
134
+ });
135
+ }
@@ -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 "./regenerateFinancialStatement";
5
+
6
+ export const regenerateFinancialStatement = defineCommand(permissions.regenerateFinancialStatement, run);
@@ -0,0 +1,129 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createMockDb } from "../../../testing/index";
3
+ import type { Transaction } from "../generated/kysely-tailordb";
4
+ import {
5
+ FinancialStatementNotFoundError,
6
+ StatementAlreadyFinalizedError,
7
+ TrialBalanceNotFoundError,
8
+ TrialBalanceImbalancedError,
9
+ ComparativeTrialBalanceNotFoundError,
10
+ } from "../lib/errors.generated";
11
+ import {
12
+ baseFinancialStatement,
13
+ finalizedFinancialStatement,
14
+ baseTrialBalance,
15
+ baseTrialBalanceLine,
16
+ baseAccount,
17
+ } from "../testing/fixtures";
18
+ import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
19
+ import { run } from "./regenerateFinancialStatement";
20
+
21
+ describe("regenerateFinancialStatement", () => {
22
+ it("returns error when financial statement does not exist", async () => {
23
+ const { db, spies } = createMockDb<Transaction>();
24
+ spies.select.mockReturnValueOnce(undefined); // statement lookup
25
+
26
+ const result = await run(db, { id: "nonexistent" }, commandCtx);
27
+
28
+ expectErr(result, FinancialStatementNotFoundError);
29
+ });
30
+
31
+ it("returns error when financial statement is already FINALIZED", async () => {
32
+ const { db, spies } = createMockDb<Transaction>();
33
+ spies.select.mockReturnValueOnce(finalizedFinancialStatement); // statement lookup
34
+
35
+ const result = await run(db, { id: finalizedFinancialStatement.id }, commandCtx);
36
+
37
+ expectErr(result, StatementAlreadyFinalizedError);
38
+ });
39
+
40
+ it("returns error when trial balance is not found", async () => {
41
+ const { db, spies } = createMockDb<Transaction>();
42
+ spies.select.mockReturnValueOnce(baseFinancialStatement); // statement lookup
43
+ spies.select.mockReturnValueOnce(undefined); // trial balance lookup
44
+
45
+ const result = await run(db, { id: baseFinancialStatement.id }, commandCtx);
46
+
47
+ expectErr(result, TrialBalanceNotFoundError);
48
+ });
49
+
50
+ it("returns error when trial balance is imbalanced", async () => {
51
+ const imbalancedTrialBalance = {
52
+ ...baseTrialBalance,
53
+ isBalanced: false,
54
+ totalDebits: 10000,
55
+ totalCredits: 9000,
56
+ };
57
+ const { db, spies } = createMockDb<Transaction>();
58
+ spies.select.mockReturnValueOnce(baseFinancialStatement); // statement lookup
59
+ spies.select.mockReturnValueOnce(imbalancedTrialBalance); // trial balance lookup
60
+
61
+ const result = await run(db, { id: baseFinancialStatement.id }, commandCtx);
62
+
63
+ expectErr(result, TrialBalanceImbalancedError);
64
+ });
65
+
66
+ it("returns error when comparative trial balance is not found", async () => {
67
+ const { db, spies } = createMockDb<Transaction>();
68
+ const statementWithComparative = {
69
+ ...baseFinancialStatement,
70
+ comparativePeriodTrialBalanceId: "comparative-tb-1",
71
+ };
72
+ spies.select.mockReturnValueOnce(statementWithComparative); // statement lookup
73
+ spies.select.mockReturnValueOnce(baseTrialBalance); // trial balance lookup
74
+ spies.select.mockReturnValueOnce(undefined); // comparative trial balance lookup - not found
75
+
76
+ const result = await run(db, { id: baseFinancialStatement.id }, commandCtx);
77
+
78
+ expectErr(result, ComparativeTrialBalanceNotFoundError);
79
+ });
80
+
81
+ it("regenerates statement with fresh data and updates generatedAt", async () => {
82
+ const { db, spies } = createMockDb<Transaction>();
83
+ const updatedStatement = {
84
+ ...baseFinancialStatement,
85
+ generatedAt: new Date(),
86
+ updatedAt: new Date(),
87
+ };
88
+
89
+ spies.select.mockReturnValueOnce(baseFinancialStatement); // statement lookup
90
+ spies.select.mockReturnValueOnce(baseTrialBalance); // trial balance lookup
91
+ spies.select.mockReturnValueOnce([baseTrialBalanceLine]); // trial balance lines (execute)
92
+ spies.select.mockReturnValueOnce(baseAccount); // account lookup for line
93
+ spies.insert.mockReturnValue({}); // line item insert
94
+ spies.update.mockReturnValueOnce(updatedStatement); // statement update
95
+
96
+ const result = await run(db, { id: baseFinancialStatement.id }, commandCtx);
97
+
98
+ const value = expectOk(result);
99
+ expect(value.financialStatement).toBeDefined();
100
+ expect(value.financialStatement.generatedAt).toBeDefined();
101
+ });
102
+
103
+ it("emits audit event recording statement regeneration", async () => {
104
+ const { db, spies } = createMockDb<Transaction>();
105
+ const updatedStatement = {
106
+ ...baseFinancialStatement,
107
+ generatedAt: new Date(),
108
+ updatedAt: new Date(),
109
+ };
110
+
111
+ spies.select.mockReturnValueOnce(baseFinancialStatement); // statement lookup
112
+ spies.select.mockReturnValueOnce(baseTrialBalance); // trial balance lookup
113
+ spies.select.mockReturnValueOnce([baseTrialBalanceLine]); // trial balance lines (execute)
114
+ spies.select.mockReturnValueOnce(baseAccount); // account lookup for line
115
+ spies.insert.mockReturnValue({}); // line item insert
116
+ spies.update.mockReturnValueOnce(updatedStatement); // statement update
117
+
118
+ const result = await run(db, { id: baseFinancialStatement.id }, commandCtx);
119
+
120
+ const value = expectOk(result);
121
+ expect(value.auditTrail).toBeDefined();
122
+ expect(value.auditTrail).toContainEqual(
123
+ expect.objectContaining({
124
+ type: "STATEMENT_REGENERATED",
125
+ actorId: commandCtx.actorId,
126
+ }),
127
+ );
128
+ });
129
+ });