@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.
- package/CHANGELOG.md +14 -0
- package/README.md +10 -10
- package/dist/cli.mjs +407 -69
- package/package.json +1 -1
- package/skills/erp-kit-app-1-requirements/SKILL.md +33 -17
- package/skills/erp-kit-app-2-requirements-review/SKILL.md +12 -0
- package/skills/erp-kit-app-3-plan/SKILL.md +18 -4
- package/skills/erp-kit-app-3-plan/references/resolver-extraction.md +1 -1
- package/skills/erp-kit-app-3-plan/references/screen-extraction.md +1 -1
- package/skills/erp-kit-app-4-plan-review/SKILL.md +12 -0
- package/skills/erp-kit-app-5-impl-backend/SKILL.md +12 -0
- package/skills/erp-kit-app-6-impl-frontend/SKILL.md +12 -0
- package/skills/erp-kit-app-7-impl-review/SKILL.md +13 -1
- package/skills/erp-kit-app-shared/references/progress-protocol.md +77 -0
- package/skills/erp-kit-mock-scenario/SKILL.md +1 -1
- package/skills/erp-kit-module-1-requirements/SKILL.md +1 -1
- package/skills/erp-kit-module-3-plan/SKILL.md +3 -3
- package/skills/erp-kit-module-3-update-plan/SKILL.md +3 -3
- package/skills/erp-kit-module-5-impl/SKILL.md +1 -1
- package/src/commands/app/index.ts +2 -0
- package/src/commands/app/progress/git-context.ts +16 -0
- package/src/commands/app/progress/index.ts +45 -0
- package/src/commands/app/progress/log.ts +49 -0
- package/src/commands/app/progress/progress.test.ts +128 -0
- package/src/commands/app/progress/schema-cmd.ts +10 -0
- package/src/commands/check.test.ts +4 -4
- package/src/commands/lib/discovery.test.ts +5 -7
- package/src/commands/lib/discovery.ts +8 -8
- package/src/commands/lib/sync-check-source.test.ts +1 -1
- package/src/commands/lib/sync-check-source.ts +6 -1
- package/src/commands/lib/sync-check-tests.test.ts +43 -0
- package/src/commands/lib/sync-check-tests.ts +20 -2
- package/src/commands/sync-check.ts +3 -0
- package/src/generator/generate-app-code.test.ts +0 -6
- package/src/generator/generate-app-code.ts +3 -13
- package/src/generator/generate-code.test.ts +10 -40
- package/src/generator/generate-code.ts +6 -12
- package/src/generator/stub-templates.test.ts +0 -7
- package/src/generator/stub-templates.ts +0 -14
- package/src/modules/finance-ledger/README.md +50 -0
- package/src/modules/finance-ledger/command/.gitkeep +0 -0
- package/src/modules/finance-ledger/command/addJournalLine.generated.ts +6 -0
- package/src/modules/finance-ledger/command/addJournalLine.test.ts +438 -0
- package/src/modules/finance-ledger/command/addJournalLine.ts +122 -0
- package/src/modules/finance-ledger/command/approveAndLockPeriod.generated.ts +6 -0
- package/src/modules/finance-ledger/command/approveAndLockPeriod.test.ts +107 -0
- package/src/modules/finance-ledger/command/approveAndLockPeriod.ts +72 -0
- package/src/modules/finance-ledger/command/beginClose.generated.ts +6 -0
- package/src/modules/finance-ledger/command/beginClose.test.ts +106 -0
- package/src/modules/finance-ledger/command/beginClose.ts +58 -0
- package/src/modules/finance-ledger/command/closePeriod.generated.ts +6 -0
- package/src/modules/finance-ledger/command/closePeriod.test.ts +87 -0
- package/src/modules/finance-ledger/command/closePeriod.ts +44 -0
- package/src/modules/finance-ledger/command/createAccountingPeriod.generated.ts +6 -0
- package/src/modules/finance-ledger/command/createAccountingPeriod.test.ts +425 -0
- package/src/modules/finance-ledger/command/createAccountingPeriod.ts +133 -0
- package/src/modules/finance-ledger/command/createFiscalYear.generated.ts +6 -0
- package/src/modules/finance-ledger/command/createFiscalYear.test.ts +197 -0
- package/src/modules/finance-ledger/command/createFiscalYear.ts +70 -0
- package/src/modules/finance-ledger/command/createJournalEntry.generated.ts +6 -0
- package/src/modules/finance-ledger/command/createJournalEntry.test.ts +261 -0
- package/src/modules/finance-ledger/command/createJournalEntry.ts +121 -0
- package/src/modules/finance-ledger/command/deleteAccountingPeriod.generated.ts +6 -0
- package/src/modules/finance-ledger/command/deleteAccountingPeriod.test.ts +71 -0
- package/src/modules/finance-ledger/command/deleteAccountingPeriod.ts +55 -0
- package/src/modules/finance-ledger/command/deleteFiscalYear.generated.ts +6 -0
- package/src/modules/finance-ledger/command/deleteFiscalYear.test.ts +38 -0
- package/src/modules/finance-ledger/command/deleteFiscalYear.ts +34 -0
- package/src/modules/finance-ledger/command/deleteJournalEntry.generated.ts +6 -0
- package/src/modules/finance-ledger/command/deleteJournalEntry.test.ts +58 -0
- package/src/modules/finance-ledger/command/deleteJournalEntry.ts +43 -0
- package/src/modules/finance-ledger/command/executeYearEndClose.generated.ts +6 -0
- package/src/modules/finance-ledger/command/executeYearEndClose.test.ts +239 -0
- package/src/modules/finance-ledger/command/executeYearEndClose.ts +415 -0
- package/src/modules/finance-ledger/command/finalCloseAndLockPeriod.generated.ts +6 -0
- package/src/modules/finance-ledger/command/finalCloseAndLockPeriod.test.ts +102 -0
- package/src/modules/finance-ledger/command/finalCloseAndLockPeriod.ts +76 -0
- package/src/modules/finance-ledger/command/finalizeFinancialStatement.generated.ts +6 -0
- package/src/modules/finance-ledger/command/finalizeFinancialStatement.test.ts +73 -0
- package/src/modules/finance-ledger/command/finalizeFinancialStatement.ts +73 -0
- package/src/modules/finance-ledger/command/generateFinancialStatement.generated.ts +6 -0
- package/src/modules/finance-ledger/command/generateFinancialStatement.test.ts +311 -0
- package/src/modules/finance-ledger/command/generateFinancialStatement.ts +275 -0
- package/src/modules/finance-ledger/command/generatePreliminaryStatements.generated.ts +6 -0
- package/src/modules/finance-ledger/command/generatePreliminaryStatements.test.ts +152 -0
- package/src/modules/finance-ledger/command/generatePreliminaryStatements.ts +140 -0
- package/src/modules/finance-ledger/command/generateTrialBalance.generated.ts +6 -0
- package/src/modules/finance-ledger/command/generateTrialBalance.test.ts +439 -0
- package/src/modules/finance-ledger/command/generateTrialBalance.ts +268 -0
- package/src/modules/finance-ledger/command/initiatePeriodClose.generated.ts +6 -0
- package/src/modules/finance-ledger/command/initiatePeriodClose.test.ts +153 -0
- package/src/modules/finance-ledger/command/initiatePeriodClose.ts +84 -0
- package/src/modules/finance-ledger/command/openForAdvanceEntry.generated.ts +6 -0
- package/src/modules/finance-ledger/command/openForAdvanceEntry.test.ts +87 -0
- package/src/modules/finance-ledger/command/openForAdvanceEntry.ts +44 -0
- package/src/modules/finance-ledger/command/openPeriod.generated.ts +6 -0
- package/src/modules/finance-ledger/command/openPeriod.test.ts +90 -0
- package/src/modules/finance-ledger/command/openPeriod.ts +44 -0
- package/src/modules/finance-ledger/command/permanentlyClosePeriod.generated.ts +6 -0
- package/src/modules/finance-ledger/command/permanentlyClosePeriod.test.ts +87 -0
- package/src/modules/finance-ledger/command/permanentlyClosePeriod.ts +48 -0
- package/src/modules/finance-ledger/command/postAdjustingEntries.generated.ts +6 -0
- package/src/modules/finance-ledger/command/postAdjustingEntries.test.ts +392 -0
- package/src/modules/finance-ledger/command/postAdjustingEntries.ts +156 -0
- package/src/modules/finance-ledger/command/postJournalEntry.generated.ts +6 -0
- package/src/modules/finance-ledger/command/postJournalEntry.test.ts +346 -0
- package/src/modules/finance-ledger/command/postJournalEntry.ts +160 -0
- package/src/modules/finance-ledger/command/processInventoryHandoff.generated.ts +6 -0
- package/src/modules/finance-ledger/command/processInventoryHandoff.test.ts +211 -0
- package/src/modules/finance-ledger/command/processInventoryHandoff.ts +133 -0
- package/src/modules/finance-ledger/command/processManufacturingHandoff.generated.ts +6 -0
- package/src/modules/finance-ledger/command/processManufacturingHandoff.test.ts +221 -0
- package/src/modules/finance-ledger/command/processManufacturingHandoff.ts +133 -0
- package/src/modules/finance-ledger/command/processPurchaseHandoff.generated.ts +6 -0
- package/src/modules/finance-ledger/command/processPurchaseHandoff.test.ts +222 -0
- package/src/modules/finance-ledger/command/processPurchaseHandoff.ts +133 -0
- package/src/modules/finance-ledger/command/processSalesHandoff.generated.ts +6 -0
- package/src/modules/finance-ledger/command/processSalesHandoff.test.ts +257 -0
- package/src/modules/finance-ledger/command/processSalesHandoff.ts +135 -0
- package/src/modules/finance-ledger/command/regenerateFinancialStatement.generated.ts +6 -0
- package/src/modules/finance-ledger/command/regenerateFinancialStatement.test.ts +129 -0
- package/src/modules/finance-ledger/command/regenerateFinancialStatement.ts +186 -0
- package/src/modules/finance-ledger/command/removeJournalLine.generated.ts +6 -0
- package/src/modules/finance-ledger/command/removeJournalLine.test.ts +65 -0
- package/src/modules/finance-ledger/command/removeJournalLine.ts +39 -0
- package/src/modules/finance-ledger/command/reopenPeriod.generated.ts +6 -0
- package/src/modules/finance-ledger/command/reopenPeriod.test.ts +87 -0
- package/src/modules/finance-ledger/command/reopenPeriod.ts +44 -0
- package/src/modules/finance-ledger/command/reverseJournalEntry.generated.ts +6 -0
- package/src/modules/finance-ledger/command/reverseJournalEntry.test.ts +337 -0
- package/src/modules/finance-ledger/command/reverseJournalEntry.ts +140 -0
- package/src/modules/finance-ledger/command/revertSoftLock.generated.ts +6 -0
- package/src/modules/finance-ledger/command/revertSoftLock.test.ts +96 -0
- package/src/modules/finance-ledger/command/revertSoftLock.ts +67 -0
- package/src/modules/finance-ledger/command/updateFiscalYear.generated.ts +6 -0
- package/src/modules/finance-ledger/command/updateFiscalYear.test.ts +138 -0
- package/src/modules/finance-ledger/command/updateFiscalYear.ts +85 -0
- package/src/modules/finance-ledger/command/updateJournalEntry.generated.ts +6 -0
- package/src/modules/finance-ledger/command/updateJournalEntry.test.ts +195 -0
- package/src/modules/finance-ledger/command/updateJournalEntry.ts +86 -0
- package/src/modules/finance-ledger/command/updateJournalLine.generated.ts +6 -0
- package/src/modules/finance-ledger/command/updateJournalLine.test.ts +385 -0
- package/src/modules/finance-ledger/command/updateJournalLine.ts +155 -0
- package/src/modules/finance-ledger/command/verifySubledgerTransfers.generated.ts +6 -0
- package/src/modules/finance-ledger/command/verifySubledgerTransfers.test.ts +201 -0
- package/src/modules/finance-ledger/command/verifySubledgerTransfers.ts +113 -0
- package/src/modules/finance-ledger/command/verifyTrialBalance.generated.ts +6 -0
- package/src/modules/finance-ledger/command/verifyTrialBalance.test.ts +136 -0
- package/src/modules/finance-ledger/command/verifyTrialBalance.ts +97 -0
- package/src/modules/finance-ledger/db/.gitkeep +0 -0
- package/src/modules/finance-ledger/db/accountingPeriod.ts +58 -0
- package/src/modules/finance-ledger/db/financialStatement.ts +92 -0
- package/src/modules/finance-ledger/db/financialStatementLineItem.ts +76 -0
- package/src/modules/finance-ledger/db/fiscalYear.ts +41 -0
- package/src/modules/finance-ledger/db/journalEntry.ts +101 -0
- package/src/modules/finance-ledger/db/journalLine.ts +64 -0
- package/src/modules/finance-ledger/db/periodClose.ts +97 -0
- package/src/modules/finance-ledger/db/trialBalance.ts +63 -0
- package/src/modules/finance-ledger/db/trialBalanceLine.ts +63 -0
- package/src/modules/finance-ledger/docs/commands/AddJournalLine.md +74 -0
- package/src/modules/finance-ledger/docs/commands/ApproveAndLockPeriod.md +53 -0
- package/src/modules/finance-ledger/docs/commands/BeginClose.md +47 -0
- package/src/modules/finance-ledger/docs/commands/ClosePeriod.md +45 -0
- package/src/modules/finance-ledger/docs/commands/CreateAccountingPeriod.md +69 -0
- package/src/modules/finance-ledger/docs/commands/CreateFiscalYear.md +56 -0
- package/src/modules/finance-ledger/docs/commands/CreateJournalEntry.md +63 -0
- package/src/modules/finance-ledger/docs/commands/DeleteAccountingPeriod.md +46 -0
- package/src/modules/finance-ledger/docs/commands/DeleteFiscalYear.md +40 -0
- package/src/modules/finance-ledger/docs/commands/DeleteJournalEntry.md +44 -0
- package/src/modules/finance-ledger/docs/commands/ExecuteYearEndClose.md +81 -0
- package/src/modules/finance-ledger/docs/commands/FinalCloseAndLockPeriod.md +49 -0
- package/src/modules/finance-ledger/docs/commands/FinalizeFinancialStatement.md +43 -0
- package/src/modules/finance-ledger/docs/commands/GenerateFinancialStatement.md +86 -0
- package/src/modules/finance-ledger/docs/commands/GeneratePreliminaryStatements.md +53 -0
- package/src/modules/finance-ledger/docs/commands/GenerateTrialBalance.md +75 -0
- package/src/modules/finance-ledger/docs/commands/InitiatePeriodClose.md +58 -0
- package/src/modules/finance-ledger/docs/commands/OpenForAdvanceEntry.md +44 -0
- package/src/modules/finance-ledger/docs/commands/OpenPeriod.md +45 -0
- package/src/modules/finance-ledger/docs/commands/PermanentlyClosePeriod.md +45 -0
- package/src/modules/finance-ledger/docs/commands/PostAdjustingEntries.md +61 -0
- package/src/modules/finance-ledger/docs/commands/PostJournalEntry.md +81 -0
- package/src/modules/finance-ledger/docs/commands/ProcessInventoryHandoff.md +72 -0
- package/src/modules/finance-ledger/docs/commands/ProcessManufacturingHandoff.md +68 -0
- package/src/modules/finance-ledger/docs/commands/ProcessPurchaseHandoff.md +68 -0
- package/src/modules/finance-ledger/docs/commands/ProcessSalesHandoff.md +71 -0
- package/src/modules/finance-ledger/docs/commands/RegenerateFinancialStatement.md +60 -0
- package/src/modules/finance-ledger/docs/commands/RemoveJournalLine.md +42 -0
- package/src/modules/finance-ledger/docs/commands/ReopenPeriod.md +45 -0
- package/src/modules/finance-ledger/docs/commands/ReverseJournalEntry.md +62 -0
- package/src/modules/finance-ledger/docs/commands/RevertSoftLock.md +49 -0
- package/src/modules/finance-ledger/docs/commands/UpdateFiscalYear.md +60 -0
- package/src/modules/finance-ledger/docs/commands/UpdateJournalEntry.md +50 -0
- package/src/modules/finance-ledger/docs/commands/UpdateJournalLine.md +61 -0
- package/src/modules/finance-ledger/docs/commands/VerifySubledgerTransfers.md +59 -0
- package/src/modules/finance-ledger/docs/commands/VerifyTrialBalance.md +53 -0
- package/src/modules/finance-ledger/docs/features/accounting-period-management.md +110 -0
- package/src/modules/finance-ledger/docs/features/financial-statement-generation.md +115 -0
- package/src/modules/finance-ledger/docs/features/journal-entry-management.md +138 -0
- package/src/modules/finance-ledger/docs/features/period-end-close.md +102 -0
- package/src/modules/finance-ledger/docs/features/subledger-integration.md +141 -0
- package/src/modules/finance-ledger/docs/features/trial-balance.md +99 -0
- package/src/modules/finance-ledger/docs/features/year-end-close.md +84 -0
- package/src/modules/finance-ledger/docs/models/AccountingPeriod.md +71 -0
- package/src/modules/finance-ledger/docs/models/FinancialStatement.md +76 -0
- package/src/modules/finance-ledger/docs/models/FinancialStatementLineItem.md +41 -0
- package/src/modules/finance-ledger/docs/models/FiscalYear.md +41 -0
- package/src/modules/finance-ledger/docs/models/JournalEntry.md +80 -0
- package/src/modules/finance-ledger/docs/models/JournalLine.md +47 -0
- package/src/modules/finance-ledger/docs/models/PeriodClose.md +83 -0
- package/src/modules/finance-ledger/docs/models/TrialBalance.md +56 -0
- package/src/modules/finance-ledger/docs/models/TrialBalanceLine.md +37 -0
- package/src/modules/finance-ledger/docs/queries/GetAccountingPeriod.md +35 -0
- package/src/modules/finance-ledger/docs/queries/GetFinancialStatement.md +38 -0
- package/src/modules/finance-ledger/docs/queries/GetFiscalYear.md +35 -0
- package/src/modules/finance-ledger/docs/queries/GetJournalEntry.md +37 -0
- package/src/modules/finance-ledger/docs/queries/GetPeriodByDate.md +38 -0
- package/src/modules/finance-ledger/docs/queries/GetPeriodClose.md +36 -0
- package/src/modules/finance-ledger/docs/queries/GetSubledgerTransferStatus.md +45 -0
- package/src/modules/finance-ledger/docs/queries/GetTrialBalance.md +38 -0
- package/src/modules/finance-ledger/docs/queries/ListAccountingPeriods.md +46 -0
- package/src/modules/finance-ledger/docs/queries/ListFinancialStatements.md +46 -0
- package/src/modules/finance-ledger/docs/queries/ListFiscalYears.md +42 -0
- package/src/modules/finance-ledger/docs/queries/ListJournalEntries.md +48 -0
- package/src/modules/finance-ledger/docs/queries/ListPeriodCloses.md +46 -0
- package/src/modules/finance-ledger/docs/queries/ListTrialBalances.md +51 -0
- package/src/modules/finance-ledger/executor/.gitkeep +0 -0
- package/src/modules/finance-ledger/generated/enums.ts +109 -0
- package/src/modules/finance-ledger/generated/kysely-tailordb.ts +202 -0
- package/src/modules/finance-ledger/index.ts +2 -0
- package/src/modules/finance-ledger/lib/_db_deps.ts +56 -0
- package/src/modules/finance-ledger/lib/errors.generated.ts +332 -0
- package/src/modules/finance-ledger/lib/permissions.generated.ts +41 -0
- package/src/modules/finance-ledger/lib/types.ts +66 -0
- package/src/modules/finance-ledger/module.ts +262 -0
- package/src/modules/finance-ledger/package.json +26 -0
- package/src/modules/finance-ledger/permissions.ts +3 -0
- package/src/modules/finance-ledger/query/.gitkeep +0 -0
- package/src/modules/finance-ledger/query/getAccountingPeriod.generated.ts +5 -0
- package/src/modules/finance-ledger/query/getAccountingPeriod.test.ts +31 -0
- package/src/modules/finance-ledger/query/getAccountingPeriod.ts +21 -0
- package/src/modules/finance-ledger/query/getFinancialStatement.generated.ts +5 -0
- package/src/modules/finance-ledger/query/getFinancialStatement.test.ts +35 -0
- package/src/modules/finance-ledger/query/getFinancialStatement.ts +29 -0
- package/src/modules/finance-ledger/query/getFiscalYear.generated.ts +5 -0
- package/src/modules/finance-ledger/query/getFiscalYear.test.ts +31 -0
- package/src/modules/finance-ledger/query/getFiscalYear.ts +21 -0
- package/src/modules/finance-ledger/query/getJournalEntry.generated.ts +5 -0
- package/src/modules/finance-ledger/query/getJournalEntry.test.ts +35 -0
- package/src/modules/finance-ledger/query/getJournalEntry.ts +29 -0
- package/src/modules/finance-ledger/query/getPeriodByDate.generated.ts +5 -0
- package/src/modules/finance-ledger/query/getPeriodByDate.test.ts +53 -0
- package/src/modules/finance-ledger/query/getPeriodByDate.ts +27 -0
- package/src/modules/finance-ledger/query/getPeriodClose.generated.ts +5 -0
- package/src/modules/finance-ledger/query/getPeriodClose.test.ts +31 -0
- package/src/modules/finance-ledger/query/getPeriodClose.ts +21 -0
- package/src/modules/finance-ledger/query/getSubledgerTransferStatus.generated.ts +5 -0
- package/src/modules/finance-ledger/query/getSubledgerTransferStatus.test.ts +101 -0
- package/src/modules/finance-ledger/query/getSubledgerTransferStatus.ts +68 -0
- package/src/modules/finance-ledger/query/getTrialBalance.generated.ts +5 -0
- package/src/modules/finance-ledger/query/getTrialBalance.test.ts +33 -0
- package/src/modules/finance-ledger/query/getTrialBalance.ts +30 -0
- package/src/modules/finance-ledger/query/listAccountingPeriods.generated.ts +5 -0
- package/src/modules/finance-ledger/query/listAccountingPeriods.test.ts +81 -0
- package/src/modules/finance-ledger/query/listAccountingPeriods.ts +61 -0
- package/src/modules/finance-ledger/query/listFinancialStatements.generated.ts +5 -0
- package/src/modules/finance-ledger/query/listFinancialStatements.test.ts +76 -0
- package/src/modules/finance-ledger/query/listFinancialStatements.ts +62 -0
- package/src/modules/finance-ledger/query/listFiscalYears.generated.ts +5 -0
- package/src/modules/finance-ledger/query/listFiscalYears.test.ts +63 -0
- package/src/modules/finance-ledger/query/listFiscalYears.ts +45 -0
- package/src/modules/finance-ledger/query/listJournalEntries.generated.ts +5 -0
- package/src/modules/finance-ledger/query/listJournalEntries.test.ts +91 -0
- package/src/modules/finance-ledger/query/listJournalEntries.ts +64 -0
- package/src/modules/finance-ledger/query/listPeriodCloses.generated.ts +5 -0
- package/src/modules/finance-ledger/query/listPeriodCloses.test.ts +63 -0
- package/src/modules/finance-ledger/query/listPeriodCloses.ts +64 -0
- package/src/modules/finance-ledger/query/listTrialBalances.generated.ts +5 -0
- package/src/modules/finance-ledger/query/listTrialBalances.test.ts +78 -0
- package/src/modules/finance-ledger/query/listTrialBalances.ts +56 -0
- package/src/modules/finance-ledger/seed/index.ts +19 -0
- package/src/modules/finance-ledger/tailor.config.ts +13 -0
- package/src/modules/finance-ledger/tailor.d.ts +13 -0
- package/src/modules/finance-ledger/testing/commandTestUtils.ts +35 -0
- package/src/modules/finance-ledger/testing/fixtures.ts +382 -0
- package/src/modules/finance-ledger/tsconfig.json +16 -0
- package/src/progress/schema.test.ts +161 -0
- package/src/progress/schema.ts +316 -0
- package/templates/scaffold/app/backend/package.json +1 -3
- package/templates/scaffold/app/backend/vitest.config.ts +4 -21
- package/src/generator/generate-stubs.ts +0 -35
|
@@ -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 "./initiatePeriodClose";
|
|
5
|
+
|
|
6
|
+
export const initiatePeriodClose = defineCommand(permissions.initiatePeriodClose, run);
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { createMockDb } from "../../../testing/index";
|
|
3
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
4
|
+
import {
|
|
5
|
+
AccountingPeriodNotFoundError,
|
|
6
|
+
InvalidPeriodStatusError,
|
|
7
|
+
CloseAlreadyInProgressError,
|
|
8
|
+
ConcurrentCloseConflictError,
|
|
9
|
+
} from "../lib/errors.generated";
|
|
10
|
+
import {
|
|
11
|
+
baseAccountingPeriod,
|
|
12
|
+
neverOpenedPeriod,
|
|
13
|
+
closedPeriod,
|
|
14
|
+
permanentlyClosedPeriod,
|
|
15
|
+
basePeriodClose,
|
|
16
|
+
} from "../testing/fixtures";
|
|
17
|
+
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
|
|
18
|
+
import { run } from "./initiatePeriodClose";
|
|
19
|
+
|
|
20
|
+
describe("initiatePeriodClose", () => {
|
|
21
|
+
it("returns error when accounting period does not exist", async () => {
|
|
22
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
23
|
+
spies.select.mockReturnValueOnce(undefined); // period lookup
|
|
24
|
+
|
|
25
|
+
const result = await run(db, { accountingPeriodId: "nonexistent" }, commandCtx);
|
|
26
|
+
|
|
27
|
+
expectErr(result, AccountingPeriodNotFoundError);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("returns error when accounting period is in NEVER_OPENED status", async () => {
|
|
31
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
32
|
+
spies.select.mockReturnValueOnce(neverOpenedPeriod); // period lookup
|
|
33
|
+
|
|
34
|
+
const result = await run(db, { accountingPeriodId: neverOpenedPeriod.id }, commandCtx);
|
|
35
|
+
|
|
36
|
+
expectErr(result, InvalidPeriodStatusError);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("returns error when accounting period is in CLOSED status", async () => {
|
|
40
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
41
|
+
spies.select.mockReturnValueOnce(closedPeriod); // period lookup
|
|
42
|
+
|
|
43
|
+
const result = await run(db, { accountingPeriodId: closedPeriod.id }, commandCtx);
|
|
44
|
+
|
|
45
|
+
expectErr(result, InvalidPeriodStatusError);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("returns error when accounting period is in PERMANENTLY_CLOSED status", async () => {
|
|
49
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
50
|
+
spies.select.mockReturnValueOnce(permanentlyClosedPeriod); // period lookup
|
|
51
|
+
|
|
52
|
+
const result = await run(db, { accountingPeriodId: permanentlyClosedPeriod.id }, commandCtx);
|
|
53
|
+
|
|
54
|
+
expectErr(result, InvalidPeriodStatusError);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("returns error when period already has an active close in progress", async () => {
|
|
58
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
59
|
+
spies.select
|
|
60
|
+
.mockReturnValueOnce(baseAccountingPeriod) // period lookup
|
|
61
|
+
.mockReturnValueOnce(basePeriodClose); // existing active PeriodClose
|
|
62
|
+
|
|
63
|
+
const result = await run(db, { accountingPeriodId: baseAccountingPeriod.id }, commandCtx);
|
|
64
|
+
|
|
65
|
+
expectErr(result, CloseAlreadyInProgressError);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("returns error on concurrent close attempt for the same period", async () => {
|
|
69
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
70
|
+
spies.select
|
|
71
|
+
.mockReturnValueOnce(baseAccountingPeriod) // period lookup
|
|
72
|
+
.mockReturnValueOnce(undefined); // no existing PeriodClose
|
|
73
|
+
spies.insert.mockImplementationOnce(() => {
|
|
74
|
+
throw new Error("unique constraint violation");
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const result = await run(db, { accountingPeriodId: baseAccountingPeriod.id }, commandCtx);
|
|
78
|
+
|
|
79
|
+
expectErr(result, ConcurrentCloseConflictError);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("creates PeriodClose in NOT_STARTED status for an OPEN period", async () => {
|
|
83
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
84
|
+
const createdPeriodClose = {
|
|
85
|
+
...basePeriodClose,
|
|
86
|
+
initiatedByUserId: commandCtx.actorId,
|
|
87
|
+
};
|
|
88
|
+
spies.select
|
|
89
|
+
.mockReturnValueOnce(baseAccountingPeriod) // period lookup
|
|
90
|
+
.mockReturnValueOnce(undefined); // no existing PeriodClose
|
|
91
|
+
spies.insert.mockReturnValueOnce(createdPeriodClose);
|
|
92
|
+
|
|
93
|
+
const result = await run(db, { accountingPeriodId: baseAccountingPeriod.id }, commandCtx);
|
|
94
|
+
|
|
95
|
+
const value = expectOk(result);
|
|
96
|
+
expect(value.periodClose.status).toBe("NOT_STARTED");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("records the initiating user's userId", async () => {
|
|
100
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
101
|
+
const createdPeriodClose = {
|
|
102
|
+
...basePeriodClose,
|
|
103
|
+
initiatedByUserId: commandCtx.actorId,
|
|
104
|
+
};
|
|
105
|
+
spies.select
|
|
106
|
+
.mockReturnValueOnce(baseAccountingPeriod) // period lookup
|
|
107
|
+
.mockReturnValueOnce(undefined); // no existing PeriodClose
|
|
108
|
+
spies.insert.mockReturnValueOnce(createdPeriodClose);
|
|
109
|
+
|
|
110
|
+
const result = await run(db, { accountingPeriodId: baseAccountingPeriod.id }, commandCtx);
|
|
111
|
+
|
|
112
|
+
const value = expectOk(result);
|
|
113
|
+
expect(value.periodClose.initiatedByUserId).toBe(commandCtx.actorId);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("sets completionPercentage to 0", async () => {
|
|
117
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
118
|
+
const createdPeriodClose = {
|
|
119
|
+
...basePeriodClose,
|
|
120
|
+
initiatedByUserId: commandCtx.actorId,
|
|
121
|
+
completionPercentage: 0,
|
|
122
|
+
};
|
|
123
|
+
spies.select
|
|
124
|
+
.mockReturnValueOnce(baseAccountingPeriod) // period lookup
|
|
125
|
+
.mockReturnValueOnce(undefined); // no existing PeriodClose
|
|
126
|
+
spies.insert.mockReturnValueOnce(createdPeriodClose);
|
|
127
|
+
|
|
128
|
+
const result = await run(db, { accountingPeriodId: baseAccountingPeriod.id }, commandCtx);
|
|
129
|
+
|
|
130
|
+
const value = expectOk(result);
|
|
131
|
+
expect(value.periodClose.completionPercentage).toBe(0);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("emits audit event recording acting user, timestamp, and period reference", async () => {
|
|
135
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
136
|
+
const createdPeriodClose = {
|
|
137
|
+
...basePeriodClose,
|
|
138
|
+
initiatedByUserId: commandCtx.actorId,
|
|
139
|
+
};
|
|
140
|
+
spies.select
|
|
141
|
+
.mockReturnValueOnce(baseAccountingPeriod) // period lookup
|
|
142
|
+
.mockReturnValueOnce(undefined); // no existing PeriodClose
|
|
143
|
+
spies.insert.mockReturnValueOnce(createdPeriodClose);
|
|
144
|
+
|
|
145
|
+
const result = await run(db, { accountingPeriodId: baseAccountingPeriod.id }, commandCtx);
|
|
146
|
+
|
|
147
|
+
const value = expectOk(result);
|
|
148
|
+
expect(value.auditEvent).toBeDefined();
|
|
149
|
+
expect(value.auditEvent.actorId).toBe(commandCtx.actorId);
|
|
150
|
+
expect(value.auditEvent.timestamp).toBeInstanceOf(Date);
|
|
151
|
+
expect(value.auditEvent.accountingPeriodId).toBe(baseAccountingPeriod.id);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";
|
|
2
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
3
|
+
import {
|
|
4
|
+
AccountingPeriodNotFoundError,
|
|
5
|
+
InvalidPeriodStatusError,
|
|
6
|
+
CloseAlreadyInProgressError,
|
|
7
|
+
ConcurrentCloseConflictError,
|
|
8
|
+
} from "../lib/errors.generated";
|
|
9
|
+
|
|
10
|
+
export interface InitiatePeriodCloseInput {
|
|
11
|
+
accountingPeriodId: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const TERMINAL_PERIOD_CLOSE_STATUSES = ["PERMANENTLY_CLOSED"];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Function: initiatePeriodClose
|
|
18
|
+
*
|
|
19
|
+
* Creates a new PeriodClose record in NOT_STARTED status for a given
|
|
20
|
+
* accounting period. Only periods in OPEN status can have a close initiated,
|
|
21
|
+
* and each period can have at most one active PeriodClose record.
|
|
22
|
+
*/
|
|
23
|
+
export async function run(db: Transaction, input: InitiatePeriodCloseInput, ctx: CommandContext) {
|
|
24
|
+
const { accountingPeriodId } = input;
|
|
25
|
+
|
|
26
|
+
// 1. Find accounting period
|
|
27
|
+
const period = await db
|
|
28
|
+
.selectFrom("AccountingPeriod")
|
|
29
|
+
.selectAll()
|
|
30
|
+
.where("id", "=", accountingPeriodId)
|
|
31
|
+
.forUpdate()
|
|
32
|
+
.executeTakeFirst();
|
|
33
|
+
|
|
34
|
+
if (!period) {
|
|
35
|
+
return err(new AccountingPeriodNotFoundError(accountingPeriodId));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2. Validate period is in OPEN status
|
|
39
|
+
if (period.status !== "OPEN") {
|
|
40
|
+
return err(new InvalidPeriodStatusError(accountingPeriodId));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 3. Check for existing active PeriodClose record
|
|
44
|
+
const existingClose = await db
|
|
45
|
+
.selectFrom("PeriodClose")
|
|
46
|
+
.selectAll()
|
|
47
|
+
.where("accountingPeriodId", "=", accountingPeriodId)
|
|
48
|
+
.forUpdate()
|
|
49
|
+
.executeTakeFirst();
|
|
50
|
+
|
|
51
|
+
if (existingClose && !TERMINAL_PERIOD_CLOSE_STATUSES.includes(existingClose.status)) {
|
|
52
|
+
return err(new CloseAlreadyInProgressError(accountingPeriodId));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 4. Create PeriodClose record in NOT_STARTED status
|
|
56
|
+
const now = new Date();
|
|
57
|
+
let periodClose;
|
|
58
|
+
try {
|
|
59
|
+
periodClose = await db
|
|
60
|
+
.insertInto("PeriodClose")
|
|
61
|
+
.values({
|
|
62
|
+
accountingPeriodId,
|
|
63
|
+
status: "NOT_STARTED",
|
|
64
|
+
initiatedByUserId: ctx.actorId,
|
|
65
|
+
completionPercentage: 0,
|
|
66
|
+
yearEndCloseExecuted: false,
|
|
67
|
+
createdAt: now,
|
|
68
|
+
})
|
|
69
|
+
.returningAll()
|
|
70
|
+
.executeTakeFirstOrThrow();
|
|
71
|
+
} catch {
|
|
72
|
+
return err(new ConcurrentCloseConflictError(accountingPeriodId));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 5. Build audit event
|
|
76
|
+
const auditEvent = {
|
|
77
|
+
type: "PERIOD_CLOSE_INITIATED",
|
|
78
|
+
actorId: ctx.actorId,
|
|
79
|
+
timestamp: now,
|
|
80
|
+
accountingPeriodId,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return ok({ periodClose, auditEvent });
|
|
84
|
+
}
|
|
@@ -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 "./openForAdvanceEntry";
|
|
5
|
+
|
|
6
|
+
export const openForAdvanceEntry = defineCommand(permissions.openForAdvanceEntry, run);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { createMockDb } from "../../../testing/index";
|
|
3
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
4
|
+
import {
|
|
5
|
+
AccountingPeriodNotFoundError,
|
|
6
|
+
InvalidStatusTransitionError,
|
|
7
|
+
} from "../lib/errors.generated";
|
|
8
|
+
import {
|
|
9
|
+
neverOpenedPeriod,
|
|
10
|
+
futureEnterablePeriod,
|
|
11
|
+
baseAccountingPeriod,
|
|
12
|
+
closedPeriod,
|
|
13
|
+
permanentlyClosedPeriod,
|
|
14
|
+
} from "../testing/fixtures";
|
|
15
|
+
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
|
|
16
|
+
import { run } from "./openForAdvanceEntry";
|
|
17
|
+
|
|
18
|
+
describe("openForAdvanceEntry", () => {
|
|
19
|
+
it("returns error when accounting period does not exist", async () => {
|
|
20
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
21
|
+
spies.select.mockReturnValueOnce(undefined);
|
|
22
|
+
|
|
23
|
+
const result = await run(db, { id: "non-existent" }, commandCtx);
|
|
24
|
+
|
|
25
|
+
expectErr(result, AccountingPeriodNotFoundError);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("returns error when period is in FUTURE_ENTERABLE status", async () => {
|
|
29
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
30
|
+
spies.select.mockReturnValueOnce(futureEnterablePeriod);
|
|
31
|
+
|
|
32
|
+
const result = await run(db, { id: futureEnterablePeriod.id }, commandCtx);
|
|
33
|
+
|
|
34
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("returns error when period is in OPEN status", async () => {
|
|
38
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
39
|
+
spies.select.mockReturnValueOnce(baseAccountingPeriod);
|
|
40
|
+
|
|
41
|
+
const result = await run(db, { id: baseAccountingPeriod.id }, commandCtx);
|
|
42
|
+
|
|
43
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns error when period is in CLOSED status", async () => {
|
|
47
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
48
|
+
spies.select.mockReturnValueOnce(closedPeriod);
|
|
49
|
+
|
|
50
|
+
const result = await run(db, { id: closedPeriod.id }, commandCtx);
|
|
51
|
+
|
|
52
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("returns error when period is in PERMANENTLY_CLOSED status", async () => {
|
|
56
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
57
|
+
spies.select.mockReturnValueOnce(permanentlyClosedPeriod);
|
|
58
|
+
|
|
59
|
+
const result = await run(db, { id: permanentlyClosedPeriod.id }, commandCtx);
|
|
60
|
+
|
|
61
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("transitions NEVER_OPENED period to FUTURE_ENTERABLE", async () => {
|
|
65
|
+
const updatedPeriod = { ...neverOpenedPeriod, status: "FUTURE_ENTERABLE" };
|
|
66
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
67
|
+
spies.select.mockReturnValueOnce(neverOpenedPeriod);
|
|
68
|
+
spies.update.mockReturnValueOnce(updatedPeriod);
|
|
69
|
+
|
|
70
|
+
const result = await run(db, { id: neverOpenedPeriod.id }, commandCtx);
|
|
71
|
+
|
|
72
|
+
const value = expectOk(result);
|
|
73
|
+
expect(value.accountingPeriod.status).toBe("FUTURE_ENTERABLE");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("emits audit event recording status transition from NEVER_OPENED to FUTURE_ENTERABLE and acting user", async () => {
|
|
77
|
+
const updatedPeriod = { ...neverOpenedPeriod, status: "FUTURE_ENTERABLE" };
|
|
78
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
79
|
+
spies.select.mockReturnValueOnce(neverOpenedPeriod);
|
|
80
|
+
spies.update.mockReturnValueOnce(updatedPeriod);
|
|
81
|
+
|
|
82
|
+
const result = await run(db, { id: neverOpenedPeriod.id }, commandCtx);
|
|
83
|
+
|
|
84
|
+
expectOk(result);
|
|
85
|
+
expect(spies.update).toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";
|
|
2
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
3
|
+
import {
|
|
4
|
+
AccountingPeriodNotFoundError,
|
|
5
|
+
InvalidStatusTransitionError,
|
|
6
|
+
} from "../lib/errors.generated";
|
|
7
|
+
|
|
8
|
+
export interface OpenForAdvanceEntryInput {
|
|
9
|
+
id: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const from = ["NEVER_OPENED"];
|
|
13
|
+
|
|
14
|
+
export async function run(db: Transaction, input: OpenForAdvanceEntryInput, ctx: CommandContext) {
|
|
15
|
+
const period = await db
|
|
16
|
+
.selectFrom("AccountingPeriod")
|
|
17
|
+
.selectAll()
|
|
18
|
+
.where("id", "=", input.id)
|
|
19
|
+
.forUpdate()
|
|
20
|
+
.executeTakeFirst();
|
|
21
|
+
|
|
22
|
+
if (!period) {
|
|
23
|
+
return err(new AccountingPeriodNotFoundError(input.id));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!from.includes(period.status as string)) {
|
|
27
|
+
return err(new InvalidStatusTransitionError(input.id));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const updated = await db
|
|
31
|
+
.updateTable("AccountingPeriod")
|
|
32
|
+
.set({
|
|
33
|
+
status: "FUTURE_ENTERABLE",
|
|
34
|
+
updatedAt: new Date(),
|
|
35
|
+
})
|
|
36
|
+
.where("id", "=", input.id)
|
|
37
|
+
.returningAll()
|
|
38
|
+
.executeTakeFirstOrThrow();
|
|
39
|
+
|
|
40
|
+
// Emit audit event recording status transition from NEVER_OPENED to FUTURE_ENTERABLE and acting user
|
|
41
|
+
void ctx;
|
|
42
|
+
|
|
43
|
+
return ok({ accountingPeriod: updated });
|
|
44
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { createMockDb } from "../../../testing/index";
|
|
3
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
4
|
+
import {
|
|
5
|
+
AccountingPeriodNotFoundError,
|
|
6
|
+
InvalidStatusTransitionError,
|
|
7
|
+
} from "../lib/errors.generated";
|
|
8
|
+
import {
|
|
9
|
+
neverOpenedPeriod,
|
|
10
|
+
futureEnterablePeriod,
|
|
11
|
+
baseAccountingPeriod,
|
|
12
|
+
closedPeriod,
|
|
13
|
+
permanentlyClosedPeriod,
|
|
14
|
+
} from "../testing/fixtures";
|
|
15
|
+
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
|
|
16
|
+
import { run } from "./openPeriod";
|
|
17
|
+
|
|
18
|
+
describe("openPeriod", () => {
|
|
19
|
+
it("returns error when accounting period does not exist", async () => {
|
|
20
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
21
|
+
spies.select.mockReturnValueOnce(undefined);
|
|
22
|
+
|
|
23
|
+
const result = await run(db, { id: "non-existent" }, commandCtx);
|
|
24
|
+
|
|
25
|
+
expectErr(result, AccountingPeriodNotFoundError);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("returns error when period is in OPEN status", async () => {
|
|
29
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
30
|
+
spies.select.mockReturnValueOnce(baseAccountingPeriod);
|
|
31
|
+
|
|
32
|
+
const result = await run(db, { id: baseAccountingPeriod.id }, commandCtx);
|
|
33
|
+
|
|
34
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("returns error when period is in CLOSED status", async () => {
|
|
38
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
39
|
+
spies.select.mockReturnValueOnce(closedPeriod);
|
|
40
|
+
|
|
41
|
+
const result = await run(db, { id: closedPeriod.id }, commandCtx);
|
|
42
|
+
|
|
43
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns error when period is in PERMANENTLY_CLOSED status", async () => {
|
|
47
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
48
|
+
spies.select.mockReturnValueOnce(permanentlyClosedPeriod);
|
|
49
|
+
|
|
50
|
+
const result = await run(db, { id: permanentlyClosedPeriod.id }, commandCtx);
|
|
51
|
+
|
|
52
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("transitions NEVER_OPENED period directly to OPEN", async () => {
|
|
56
|
+
const updatedPeriod = { ...neverOpenedPeriod, status: "OPEN" };
|
|
57
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
58
|
+
spies.select.mockReturnValueOnce(neverOpenedPeriod);
|
|
59
|
+
spies.update.mockReturnValueOnce(updatedPeriod);
|
|
60
|
+
|
|
61
|
+
const result = await run(db, { id: neverOpenedPeriod.id }, commandCtx);
|
|
62
|
+
|
|
63
|
+
const value = expectOk(result);
|
|
64
|
+
expect(value.accountingPeriod.status).toBe("OPEN");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("transitions FUTURE_ENTERABLE period to OPEN", async () => {
|
|
68
|
+
const updatedPeriod = { ...futureEnterablePeriod, status: "OPEN" };
|
|
69
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
70
|
+
spies.select.mockReturnValueOnce(futureEnterablePeriod);
|
|
71
|
+
spies.update.mockReturnValueOnce(updatedPeriod);
|
|
72
|
+
|
|
73
|
+
const result = await run(db, { id: futureEnterablePeriod.id }, commandCtx);
|
|
74
|
+
|
|
75
|
+
const value = expectOk(result);
|
|
76
|
+
expect(value.accountingPeriod.status).toBe("OPEN");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("emits audit event recording status transition and acting user", async () => {
|
|
80
|
+
const updatedPeriod = { ...neverOpenedPeriod, status: "OPEN" };
|
|
81
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
82
|
+
spies.select.mockReturnValueOnce(neverOpenedPeriod);
|
|
83
|
+
spies.update.mockReturnValueOnce(updatedPeriod);
|
|
84
|
+
|
|
85
|
+
const result = await run(db, { id: neverOpenedPeriod.id }, commandCtx);
|
|
86
|
+
|
|
87
|
+
expectOk(result);
|
|
88
|
+
expect(spies.update).toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";
|
|
2
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
3
|
+
import {
|
|
4
|
+
AccountingPeriodNotFoundError,
|
|
5
|
+
InvalidStatusTransitionError,
|
|
6
|
+
} from "../lib/errors.generated";
|
|
7
|
+
|
|
8
|
+
export interface OpenPeriodInput {
|
|
9
|
+
id: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const from = ["NEVER_OPENED", "FUTURE_ENTERABLE"];
|
|
13
|
+
|
|
14
|
+
export async function run(db: Transaction, input: OpenPeriodInput, ctx: CommandContext) {
|
|
15
|
+
const period = await db
|
|
16
|
+
.selectFrom("AccountingPeriod")
|
|
17
|
+
.selectAll()
|
|
18
|
+
.where("id", "=", input.id)
|
|
19
|
+
.forUpdate()
|
|
20
|
+
.executeTakeFirst();
|
|
21
|
+
|
|
22
|
+
if (!period) {
|
|
23
|
+
return err(new AccountingPeriodNotFoundError(input.id));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!from.includes(period.status as string)) {
|
|
27
|
+
return err(new InvalidStatusTransitionError(input.id));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const updated = await db
|
|
31
|
+
.updateTable("AccountingPeriod")
|
|
32
|
+
.set({
|
|
33
|
+
status: "OPEN",
|
|
34
|
+
updatedAt: new Date(),
|
|
35
|
+
})
|
|
36
|
+
.where("id", "=", input.id)
|
|
37
|
+
.returningAll()
|
|
38
|
+
.executeTakeFirstOrThrow();
|
|
39
|
+
|
|
40
|
+
// Emit audit event recording status transition and acting user
|
|
41
|
+
void ctx;
|
|
42
|
+
|
|
43
|
+
return ok({ accountingPeriod: updated });
|
|
44
|
+
}
|
|
@@ -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 "./permanentlyClosePeriod";
|
|
5
|
+
|
|
6
|
+
export const permanentlyClosePeriod = defineCommand(permissions.permanentlyClosePeriod, run);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { createMockDb } from "../../../testing/index";
|
|
3
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
4
|
+
import {
|
|
5
|
+
AccountingPeriodNotFoundError,
|
|
6
|
+
InvalidStatusTransitionError,
|
|
7
|
+
} from "../lib/errors.generated";
|
|
8
|
+
import {
|
|
9
|
+
neverOpenedPeriod,
|
|
10
|
+
futureEnterablePeriod,
|
|
11
|
+
baseAccountingPeriod,
|
|
12
|
+
closedPeriod,
|
|
13
|
+
permanentlyClosedPeriod,
|
|
14
|
+
} from "../testing/fixtures";
|
|
15
|
+
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
|
|
16
|
+
import { run } from "./permanentlyClosePeriod";
|
|
17
|
+
|
|
18
|
+
describe("permanentlyClosePeriod", () => {
|
|
19
|
+
it("returns error when accounting period does not exist", async () => {
|
|
20
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
21
|
+
spies.select.mockReturnValueOnce(undefined);
|
|
22
|
+
|
|
23
|
+
const result = await run(db, { id: "non-existent" }, commandCtx);
|
|
24
|
+
|
|
25
|
+
expectErr(result, AccountingPeriodNotFoundError);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("returns error when period is in NEVER_OPENED status", async () => {
|
|
29
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
30
|
+
spies.select.mockReturnValueOnce(neverOpenedPeriod);
|
|
31
|
+
|
|
32
|
+
const result = await run(db, { id: neverOpenedPeriod.id }, commandCtx);
|
|
33
|
+
|
|
34
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("returns error when period is in OPEN status", async () => {
|
|
38
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
39
|
+
spies.select.mockReturnValueOnce(baseAccountingPeriod);
|
|
40
|
+
|
|
41
|
+
const result = await run(db, { id: baseAccountingPeriod.id }, commandCtx);
|
|
42
|
+
|
|
43
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns error when period is in FUTURE_ENTERABLE status", async () => {
|
|
47
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
48
|
+
spies.select.mockReturnValueOnce(futureEnterablePeriod);
|
|
49
|
+
|
|
50
|
+
const result = await run(db, { id: futureEnterablePeriod.id }, commandCtx);
|
|
51
|
+
|
|
52
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("returns error when period is already PERMANENTLY_CLOSED", async () => {
|
|
56
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
57
|
+
spies.select.mockReturnValueOnce(permanentlyClosedPeriod);
|
|
58
|
+
|
|
59
|
+
const result = await run(db, { id: permanentlyClosedPeriod.id }, commandCtx);
|
|
60
|
+
|
|
61
|
+
expectErr(result, InvalidStatusTransitionError);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("transitions CLOSED period to PERMANENTLY_CLOSED", async () => {
|
|
65
|
+
const updatedPeriod = { ...closedPeriod, status: "PERMANENTLY_CLOSED" };
|
|
66
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
67
|
+
spies.select.mockReturnValueOnce(closedPeriod);
|
|
68
|
+
spies.update.mockReturnValueOnce(updatedPeriod);
|
|
69
|
+
|
|
70
|
+
const result = await run(db, { id: closedPeriod.id }, commandCtx);
|
|
71
|
+
|
|
72
|
+
const value = expectOk(result);
|
|
73
|
+
expect(value.accountingPeriod.status).toBe("PERMANENTLY_CLOSED");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("emits audit event recording the irreversible transition and acting user", async () => {
|
|
77
|
+
const updatedPeriod = { ...closedPeriod, status: "PERMANENTLY_CLOSED" };
|
|
78
|
+
const { db, spies } = createMockDb<Transaction>();
|
|
79
|
+
spies.select.mockReturnValueOnce(closedPeriod);
|
|
80
|
+
spies.update.mockReturnValueOnce(updatedPeriod);
|
|
81
|
+
|
|
82
|
+
const result = await run(db, { id: closedPeriod.id }, commandCtx);
|
|
83
|
+
|
|
84
|
+
expectOk(result);
|
|
85
|
+
expect(spies.update).toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";
|
|
2
|
+
import type { Transaction } from "../generated/kysely-tailordb";
|
|
3
|
+
import {
|
|
4
|
+
AccountingPeriodNotFoundError,
|
|
5
|
+
InvalidStatusTransitionError,
|
|
6
|
+
} from "../lib/errors.generated";
|
|
7
|
+
|
|
8
|
+
export interface PermanentlyClosePeriodInput {
|
|
9
|
+
id: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const from = ["CLOSED"];
|
|
13
|
+
|
|
14
|
+
export async function run(
|
|
15
|
+
db: Transaction,
|
|
16
|
+
input: PermanentlyClosePeriodInput,
|
|
17
|
+
ctx: CommandContext,
|
|
18
|
+
) {
|
|
19
|
+
const period = await db
|
|
20
|
+
.selectFrom("AccountingPeriod")
|
|
21
|
+
.selectAll()
|
|
22
|
+
.where("id", "=", input.id)
|
|
23
|
+
.forUpdate()
|
|
24
|
+
.executeTakeFirst();
|
|
25
|
+
|
|
26
|
+
if (!period) {
|
|
27
|
+
return err(new AccountingPeriodNotFoundError(input.id));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!from.includes(period.status as string)) {
|
|
31
|
+
return err(new InvalidStatusTransitionError(input.id));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const updated = await db
|
|
35
|
+
.updateTable("AccountingPeriod")
|
|
36
|
+
.set({
|
|
37
|
+
status: "PERMANENTLY_CLOSED",
|
|
38
|
+
updatedAt: new Date(),
|
|
39
|
+
})
|
|
40
|
+
.where("id", "=", input.id)
|
|
41
|
+
.returningAll()
|
|
42
|
+
.executeTakeFirstOrThrow();
|
|
43
|
+
|
|
44
|
+
// Emit audit event recording the irreversible transition and acting user
|
|
45
|
+
void ctx;
|
|
46
|
+
|
|
47
|
+
return ok({ accountingPeriod: updated });
|
|
48
|
+
}
|
|
@@ -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 "./postAdjustingEntries";
|
|
5
|
+
|
|
6
|
+
export const postAdjustingEntries = defineCommand(permissions.postAdjustingEntries, run);
|