@tailor-platform/erp-kit 0.8.0 → 0.9.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 +15 -0
- package/package.json +1 -1
- package/skills/erp-kit-app-1-requirements/SKILL.md +6 -0
- package/skills/erp-kit-app-2-requirements-review/SKILL.md +6 -0
- package/skills/erp-kit-app-3-plan/SKILL.md +6 -0
- package/skills/erp-kit-app-4-plan-review/SKILL.md +6 -0
- package/skills/erp-kit-app-5-impl-backend/SKILL.md +7 -0
- package/skills/erp-kit-app-6-impl-frontend/SKILL.md +6 -0
- package/skills/erp-kit-app-7-impl-review/SKILL.md +6 -0
- package/skills/erp-kit-app-shared/SKILL.md +2 -0
- package/skills/erp-kit-mock-scenario/SKILL.md +6 -0
- package/skills/erp-kit-module-1-requirements/SKILL.md +6 -0
- package/skills/erp-kit-module-2-requirements-review/SKILL.md +6 -0
- package/skills/erp-kit-module-3-plan/SKILL.md +6 -0
- package/skills/erp-kit-module-3-update-plan/SKILL.md +6 -0
- package/skills/erp-kit-module-4-plan-review/SKILL.md +6 -0
- package/skills/erp-kit-module-5-impl/SKILL.md +6 -0
- package/skills/erp-kit-module-6-impl-review/SKILL.md +6 -0
- package/skills/erp-kit-module-shared/SKILL.md +2 -0
- package/skills/erp-kit-module-shared/references/commands.md +3 -0
- package/skills/erp-kit-update/SKILL.md +6 -0
- package/src/modules/accounting/command/assignProfitCenterToHierarchyNode.test.ts +3 -3
- package/src/modules/accounting/command/assignProfitCenterToHierarchyNode.ts +1 -1
- package/src/modules/accounting/command/createCostCenterHierarchyNode.test.ts +3 -3
- package/src/modules/accounting/command/createCostCenterHierarchyNode.ts +1 -1
- package/src/modules/accounting/command/moveCostCenterHierarchyNode.test.ts +2 -2
- package/src/modules/accounting/command/moveCostCenterHierarchyNode.ts +1 -1
- package/src/modules/accounting/module.ts +1 -0
- package/src/modules/business-partner/command/createPartnerBankAccount.test.ts +3 -3
- package/src/modules/business-partner/command/createPartnerBankAccount.ts +1 -1
- package/src/modules/business-partner/module.ts +1 -0
- package/src/modules/coa-management/command/activateAccount.test.ts +0 -15
- package/src/modules/coa-management/command/activateAccount.ts +1 -42
- package/src/modules/coa-management/command/activateChartOfAccounts.test.ts +2 -31
- package/src/modules/coa-management/command/activateChartOfAccounts.ts +1 -37
- package/src/modules/coa-management/command/createAccount.test.ts +0 -28
- package/src/modules/coa-management/command/createAccount.ts +0 -43
- package/src/modules/coa-management/command/createAccountGroup.test.ts +2 -51
- package/src/modules/coa-management/command/createAccountGroup.ts +1 -56
- package/src/modules/coa-management/command/createChartOfAccounts.test.ts +1 -49
- package/src/modules/coa-management/command/createChartOfAccounts.ts +0 -51
- package/src/modules/coa-management/command/deactivateAccount.test.ts +0 -15
- package/src/modules/coa-management/command/deactivateAccount.ts +1 -53
- package/src/modules/coa-management/command/deactivateChartOfAccounts.test.ts +2 -29
- package/src/modules/coa-management/command/deactivateChartOfAccounts.ts +1 -37
- package/src/modules/coa-management/command/deleteAccount.test.ts +0 -13
- package/src/modules/coa-management/command/deleteAccount.ts +1 -42
- package/src/modules/coa-management/command/deleteAccountGroup.test.ts +0 -19
- package/src/modules/coa-management/command/deleteAccountGroup.ts +1 -42
- package/src/modules/coa-management/command/deleteChartOfAccounts.test.ts +2 -58
- package/src/modules/coa-management/command/deleteChartOfAccounts.ts +4 -88
- package/src/modules/coa-management/command/moveAccountGroup.test.ts +0 -27
- package/src/modules/coa-management/command/moveAccountGroup.ts +1 -48
- package/src/modules/coa-management/command/reactivateAccount.test.ts +0 -15
- package/src/modules/coa-management/command/reactivateAccount.ts +1 -53
- package/src/modules/coa-management/command/updateAccount.test.ts +0 -15
- package/src/modules/coa-management/command/updateAccount.ts +0 -92
- package/src/modules/coa-management/command/updateAccountGroup.test.ts +0 -20
- package/src/modules/coa-management/command/updateAccountGroup.ts +1 -61
- package/src/modules/coa-management/command/updateChartOfAccounts.test.ts +2 -31
- package/src/modules/coa-management/command/updateChartOfAccounts.ts +1 -50
- package/src/modules/coa-management/docs/commands/ActivateAccount.md +1 -4
- package/src/modules/coa-management/docs/commands/ActivateChartOfAccounts.md +1 -4
- package/src/modules/coa-management/docs/commands/CreateAccount.md +1 -4
- package/src/modules/coa-management/docs/commands/CreateAccountGroup.md +2 -5
- package/src/modules/coa-management/docs/commands/CreateChartOfAccounts.md +2 -6
- package/src/modules/coa-management/docs/commands/DeactivateAccount.md +1 -4
- package/src/modules/coa-management/docs/commands/DeactivateChartOfAccounts.md +1 -4
- package/src/modules/coa-management/docs/commands/DeleteAccount.md +1 -4
- package/src/modules/coa-management/docs/commands/DeleteAccountGroup.md +1 -4
- package/src/modules/coa-management/docs/commands/DeleteChartOfAccounts.md +1 -6
- package/src/modules/coa-management/docs/commands/MoveAccountGroup.md +1 -4
- package/src/modules/coa-management/docs/commands/ReactivateAccount.md +1 -4
- package/src/modules/coa-management/docs/commands/UpdateAccount.md +1 -4
- package/src/modules/coa-management/docs/commands/UpdateAccountGroup.md +2 -5
- package/src/modules/coa-management/docs/commands/UpdateChartOfAccounts.md +1 -4
- package/src/modules/coa-management/module.ts +16 -27
- package/src/modules/finance-ledger/module.ts +1 -0
- package/src/modules/inventory/command/approveInventoryAdjustment.test.ts +1 -1
- package/src/modules/inventory/command/approveInventoryAdjustment.ts +1 -1
- package/src/modules/inventory/command/cancelStockMovement.test.ts +2 -2
- package/src/modules/inventory/command/cancelStockMovement.ts +1 -1
- package/src/modules/inventory/command/confirmInventoryAdjustment.test.ts +4 -4
- package/src/modules/inventory/command/confirmInventoryAdjustment.ts +1 -1
- package/src/modules/inventory/command/confirmStockMovement.test.ts +1 -1
- package/src/modules/inventory/command/confirmStockMovement.ts +1 -1
- package/src/modules/inventory/command/createInventoryAdjustment.test.ts +6 -6
- package/src/modules/inventory/command/createInventoryAdjustment.ts +1 -1
- package/src/modules/inventory/command/createStockMovement.test.ts +3 -3
- package/src/modules/inventory/command/createStockMovement.ts +1 -1
- package/src/modules/inventory/command/executeStockMovement.test.ts +5 -5
- package/src/modules/inventory/command/executeStockMovement.ts +1 -1
- package/src/modules/inventory/command/rejectInventoryAdjustment.test.ts +1 -1
- package/src/modules/inventory/command/rejectInventoryAdjustment.ts +1 -1
- package/src/modules/inventory/command/reviseInventoryAdjustment.test.ts +2 -2
- package/src/modules/inventory/command/reviseInventoryAdjustment.ts +1 -1
- package/src/modules/inventory/command/submitInventoryAdjustment.test.ts +1 -1
- package/src/modules/inventory/command/submitInventoryAdjustment.ts +1 -1
- package/src/modules/inventory/command/updateStockMovement.test.ts +4 -4
- package/src/modules/inventory/command/updateStockMovement.ts +2 -2
- package/src/modules/inventory/module.ts +1 -0
- package/src/modules/item-management/command/createTaxonomyNode.test.ts +4 -4
- package/src/modules/item-management/command/createTaxonomyNode.ts +1 -1
- package/src/modules/item-management/command/moveTaxonomyNode.test.ts +2 -2
- package/src/modules/item-management/command/moveTaxonomyNode.ts +2 -2
- package/src/modules/item-management/command/updateTaxonomyNode.test.ts +2 -2
- package/src/modules/item-management/command/updateTaxonomyNode.ts +1 -1
- package/src/modules/item-management/module.ts +1 -0
- package/src/modules/manufacturing/command/createRouting.ts +1 -1
- package/src/modules/manufacturing/command/recordInventoryIssueOutcome.test.ts +1 -1
- package/src/modules/manufacturing/command/recordInventoryIssueOutcome.ts +1 -1
- package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.test.ts +1 -1
- package/src/modules/manufacturing/command/recordManufacturingCostSettlementAcknowledgment.ts +1 -1
- package/src/modules/manufacturing/command/reviewManufacturingCostSummary.test.ts +1 -1
- package/src/modules/manufacturing/command/reviewManufacturingCostSummary.ts +1 -1
- package/src/modules/manufacturing/command/updateRouting.ts +1 -1
- package/src/modules/manufacturing/module.ts +1 -0
- package/src/modules/organization/module.ts +1 -0
- package/src/modules/primitives/module.ts +1 -0
- package/src/modules/product-management/command/assignProductToCategory.test.ts +2 -2
- package/src/modules/product-management/command/assignProductToCategory.ts +2 -2
- package/src/modules/product-management/command/createProductAttribute.test.ts +1 -1
- package/src/modules/product-management/command/createProductAttribute.ts +1 -1
- package/src/modules/product-management/command/createProductAttributeValue.test.ts +1 -1
- package/src/modules/product-management/command/createProductAttributeValue.ts +1 -1
- package/src/modules/product-management/command/createProductCategory.test.ts +2 -2
- package/src/modules/product-management/command/createProductCategory.ts +1 -1
- package/src/modules/product-management/command/setProductAttributeAssignment.test.ts +3 -3
- package/src/modules/product-management/command/setProductAttributeAssignment.ts +2 -2
- package/src/modules/product-management/module.ts +1 -0
- package/src/modules/purchase/command/activatePurchasePaymentTerm.test.ts +4 -4
- package/src/modules/purchase/command/activatePurchasePaymentTerm.ts +2 -2
- package/src/modules/purchase/command/deactivatePurchasePaymentTerm.test.ts +4 -4
- package/src/modules/purchase/command/deactivatePurchasePaymentTerm.ts +2 -2
- package/src/modules/purchase/command/updatePurchasePaymentTerm.test.ts +2 -2
- package/src/modules/purchase/command/updatePurchasePaymentTerm.ts +1 -1
- package/src/modules/purchase/module.ts +1 -0
- package/src/modules/sales/command/createSalesOrder.ts +1 -1
- package/src/modules/sales/module.ts +1 -0
- package/templates/scaffold/app/backend/eslint.config.js +17 -0
- package/templates/scaffold/app/backend/package.json +1 -0
- package/templates/scaffold/app/backend/src/tests/stories/audit-log/user--view-audit-log-detail.test.ts +3 -3
- package/templates/scaffold/app/backend/src/tests/stories/role-management/user--assign-role-to-user.test.ts +4 -4
- package/templates/scaffold/app/backend/src/tests/stories/role-management/user--remove-role-from-user.test.ts +4 -4
- package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--toggle-user-status.test.ts +6 -6
- package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--update-own-profile.test.ts +13 -13
- package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--update-user-profile.test.ts +16 -17
- package/templates/scaffold/app/backend/src/tests/stories/user-lifecycle/user--view-user-detail.test.ts +3 -3
- package/templates/scaffold/app/backend/tailor.config.ts +15 -1
- package/templates/scaffold/app/backend/tsconfig.json +1 -1
- package/templates/scaffold/app/frontend/src/App.tsx +57 -16
- package/templates/scaffold/module/eslint.config.js +24 -0
- package/templates/scaffold/module/module.ts +1 -0
- package/templates/scaffold/module/package.json +3 -1
- package/templates/scaffold/module/vitest.config.ts +11 -0
- /package/templates/scaffold/app/frontend/src/pages/{user-management/audit → audit}/[id]/components/audit-entry-detail.tsx +0 -0
- /package/templates/scaffold/app/frontend/src/pages/{user-management/audit → audit}/[id]/page.tsx +0 -0
- /package/templates/scaffold/app/frontend/src/pages/{user-management/audit → audit}/components/audit-entries-table.tsx +0 -0
- /package/templates/scaffold/app/frontend/src/pages/{user-management/audit → audit}/page.tsx +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import type { Transaction } from "../generated/kysely-tailordb";
|
|
3
2
|
import {
|
|
4
3
|
AccountNotFoundError,
|
|
@@ -36,23 +35,6 @@ export type UpdateAccountInput = {
|
|
|
36
35
|
accountGroupId?: string | null;
|
|
37
36
|
};
|
|
38
37
|
|
|
39
|
-
export interface AuditCommands {
|
|
40
|
-
logAuditEvent: (
|
|
41
|
-
db: Transaction,
|
|
42
|
-
input: {
|
|
43
|
-
eventId: string;
|
|
44
|
-
actorType: string;
|
|
45
|
-
actorId: string;
|
|
46
|
-
entityType: string;
|
|
47
|
-
entityId: string;
|
|
48
|
-
operationType: string;
|
|
49
|
-
companyId?: string;
|
|
50
|
-
changes: { fieldName: string; oldValue?: unknown; newValue?: unknown }[];
|
|
51
|
-
},
|
|
52
|
-
ctx: CommandContext,
|
|
53
|
-
) => Promise<{ ok: true; value: unknown }>;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
38
|
interface GetCurrencyDep {
|
|
57
39
|
getCurrency: (
|
|
58
40
|
db: Transaction,
|
|
@@ -83,7 +65,6 @@ export async function run<CF extends Record<string, unknown>>(
|
|
|
83
65
|
input: UpdateAccountInput & Omit<Partial<CF>, "status">,
|
|
84
66
|
ctx: CommandContext,
|
|
85
67
|
deps?: GetCurrencyDep,
|
|
86
|
-
auditCommands?: AuditCommands,
|
|
87
68
|
) {
|
|
88
69
|
const {
|
|
89
70
|
id,
|
|
@@ -293,78 +274,5 @@ export async function run<CF extends Record<string, unknown>>(
|
|
|
293
274
|
.returningAll()
|
|
294
275
|
.executeTakeFirst();
|
|
295
276
|
|
|
296
|
-
// 12. Emit audit event
|
|
297
|
-
if (auditCommands) {
|
|
298
|
-
const changes: { fieldName: string; oldValue?: unknown; newValue?: unknown }[] = [];
|
|
299
|
-
if (name !== undefined && name !== account.name) {
|
|
300
|
-
changes.push({ fieldName: "name", oldValue: account.name, newValue: name });
|
|
301
|
-
}
|
|
302
|
-
if (code !== undefined && code !== account.code) {
|
|
303
|
-
changes.push({ fieldName: "code", oldValue: account.code, newValue: code });
|
|
304
|
-
}
|
|
305
|
-
if (accountType !== undefined && accountType !== account.accountType) {
|
|
306
|
-
changes.push({
|
|
307
|
-
fieldName: "accountType",
|
|
308
|
-
oldValue: account.accountType,
|
|
309
|
-
newValue: accountType,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
if (classification !== undefined && classification !== account.classification) {
|
|
313
|
-
changes.push({
|
|
314
|
-
fieldName: "classification",
|
|
315
|
-
oldValue: account.classification,
|
|
316
|
-
newValue: classification,
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
if (reconciliation !== undefined && reconciliation !== account.reconciliation) {
|
|
320
|
-
changes.push({
|
|
321
|
-
fieldName: "reconciliation",
|
|
322
|
-
oldValue: account.reconciliation,
|
|
323
|
-
newValue: reconciliation,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
if (currencyRestriction !== undefined && currencyRestriction !== account.currencyRestriction) {
|
|
327
|
-
changes.push({
|
|
328
|
-
fieldName: "currencyRestriction",
|
|
329
|
-
oldValue: account.currencyRestriction,
|
|
330
|
-
newValue: currencyRestriction,
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
if (defaultTaxCode !== undefined && defaultTaxCode !== account.defaultTaxCode) {
|
|
334
|
-
changes.push({
|
|
335
|
-
fieldName: "defaultTaxCode",
|
|
336
|
-
oldValue: account.defaultTaxCode,
|
|
337
|
-
newValue: defaultTaxCode,
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
if (tags !== undefined && tags !== account.tags) {
|
|
341
|
-
changes.push({ fieldName: "tags", oldValue: account.tags, newValue: tags });
|
|
342
|
-
}
|
|
343
|
-
if (accountGroupId !== undefined && accountGroupId !== account.accountGroupId) {
|
|
344
|
-
changes.push({
|
|
345
|
-
fieldName: "accountGroupId",
|
|
346
|
-
oldValue: account.accountGroupId,
|
|
347
|
-
newValue: accountGroupId,
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
if (changes.length > 0) {
|
|
352
|
-
await auditCommands.logAuditEvent(
|
|
353
|
-
db,
|
|
354
|
-
{
|
|
355
|
-
eventId: randomUUID(),
|
|
356
|
-
actorType: "USER",
|
|
357
|
-
actorId: ctx.actorId,
|
|
358
|
-
entityType: "Account",
|
|
359
|
-
entityId: id,
|
|
360
|
-
operationType: "UPDATE",
|
|
361
|
-
companyId: coa.companyId,
|
|
362
|
-
changes,
|
|
363
|
-
},
|
|
364
|
-
ctx,
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
277
|
return ok({ account: updated! });
|
|
370
278
|
}
|
|
@@ -238,26 +238,6 @@ describe("updateAccountGroup", () => {
|
|
|
238
238
|
}
|
|
239
239
|
});
|
|
240
240
|
|
|
241
|
-
it("emits audit event recording previous and new field values", async () => {
|
|
242
|
-
const { db, spies } = createMockDb<Transaction>();
|
|
243
|
-
const updatedGroup = { ...baseRootGroup, name: "Renamed Assets", updatedAt: new Date() };
|
|
244
|
-
spies.select
|
|
245
|
-
.mockReturnValueOnce(baseRootGroup) // Group lookup
|
|
246
|
-
.mockReturnValueOnce(baseActiveCoa); // CoA lookup
|
|
247
|
-
spies.update.mockReturnValue(updatedGroup);
|
|
248
|
-
|
|
249
|
-
const result = await run(db, { id: baseRootGroup.id, name: "Renamed Assets" }, ctx);
|
|
250
|
-
|
|
251
|
-
expect(result.ok).toBe(true);
|
|
252
|
-
if (result.ok) {
|
|
253
|
-
// The returned value contains all updated fields for audit logging
|
|
254
|
-
expect(result.value.accountGroup.name).toBe("Renamed Assets");
|
|
255
|
-
expect(result.value.accountGroup.updatedAt).toBeDefined();
|
|
256
|
-
}
|
|
257
|
-
expect(spies.update).toHaveBeenCalled();
|
|
258
|
-
expect(spies.set).toHaveBeenCalledWith(expect.objectContaining({ name: "Renamed Assets" }));
|
|
259
|
-
});
|
|
260
|
-
|
|
261
241
|
it("passes custom fields through to update", async () => {
|
|
262
242
|
const { db, spies } = createMockDb<Transaction>();
|
|
263
243
|
const updatedGroup = { ...baseRootGroup, customField: "custom-value" };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import type { Transaction } from "../generated/kysely-tailordb";
|
|
3
2
|
import {
|
|
4
3
|
AccountGroupNotFoundError,
|
|
@@ -19,22 +18,6 @@ export type UpdateAccountGroupInput = (
|
|
|
19
18
|
numberRangeEnd?: number | null;
|
|
20
19
|
};
|
|
21
20
|
|
|
22
|
-
export interface AuditCommands {
|
|
23
|
-
logAuditEvent: (
|
|
24
|
-
db: Transaction,
|
|
25
|
-
input: {
|
|
26
|
-
eventId: string;
|
|
27
|
-
actorType: string;
|
|
28
|
-
actorId: string;
|
|
29
|
-
entityType: string;
|
|
30
|
-
entityId: string;
|
|
31
|
-
operationType: string;
|
|
32
|
-
companyId?: string;
|
|
33
|
-
changes: { fieldName: string; oldValue?: unknown; newValue?: unknown }[];
|
|
34
|
-
},
|
|
35
|
-
ctx: CommandContext,
|
|
36
|
-
) => Promise<{ ok: true; value: unknown }>;
|
|
37
|
-
}
|
|
38
21
|
/**
|
|
39
22
|
* Function: updateAccountGroup
|
|
40
23
|
*
|
|
@@ -44,8 +27,7 @@ export interface AuditCommands {
|
|
|
44
27
|
export async function run<CF extends Record<string, unknown>>(
|
|
45
28
|
db: Transaction,
|
|
46
29
|
input: UpdateAccountGroupInput & Omit<Partial<CF>, "status">,
|
|
47
|
-
|
|
48
|
-
auditCommands?: AuditCommands,
|
|
30
|
+
_ctx: CommandContext,
|
|
49
31
|
) {
|
|
50
32
|
const { name, sortOrder, numberRangeStart, numberRangeEnd, ...customFields } = input;
|
|
51
33
|
delete (customFields as Record<string, unknown>).id;
|
|
@@ -157,47 +139,5 @@ export async function run<CF extends Record<string, unknown>>(
|
|
|
157
139
|
.returningAll()
|
|
158
140
|
.executeTakeFirst();
|
|
159
141
|
|
|
160
|
-
// 7. Emit audit event
|
|
161
|
-
if (auditCommands) {
|
|
162
|
-
const changes: { fieldName: string; oldValue?: unknown; newValue?: unknown }[] = [];
|
|
163
|
-
if (name !== undefined && name !== existing.name) {
|
|
164
|
-
changes.push({ fieldName: "name", oldValue: existing.name, newValue: name });
|
|
165
|
-
}
|
|
166
|
-
if (sortOrder !== undefined && sortOrder !== existing.sortOrder) {
|
|
167
|
-
changes.push({ fieldName: "sortOrder", oldValue: existing.sortOrder, newValue: sortOrder });
|
|
168
|
-
}
|
|
169
|
-
if (numberRangeStart !== undefined && numberRangeStart !== existing.numberRangeStart) {
|
|
170
|
-
changes.push({
|
|
171
|
-
fieldName: "numberRangeStart",
|
|
172
|
-
oldValue: existing.numberRangeStart,
|
|
173
|
-
newValue: numberRangeStart,
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
if (numberRangeEnd !== undefined && numberRangeEnd !== existing.numberRangeEnd) {
|
|
177
|
-
changes.push({
|
|
178
|
-
fieldName: "numberRangeEnd",
|
|
179
|
-
oldValue: existing.numberRangeEnd,
|
|
180
|
-
newValue: numberRangeEnd,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (changes.length > 0) {
|
|
185
|
-
await auditCommands.logAuditEvent(
|
|
186
|
-
db,
|
|
187
|
-
{
|
|
188
|
-
eventId: randomUUID(),
|
|
189
|
-
actorType: "USER",
|
|
190
|
-
actorId: ctx.actorId,
|
|
191
|
-
entityType: "AccountGroup",
|
|
192
|
-
entityId: existing.id,
|
|
193
|
-
operationType: "UPDATE",
|
|
194
|
-
companyId: coa!.companyId,
|
|
195
|
-
changes,
|
|
196
|
-
},
|
|
197
|
-
ctx,
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
142
|
return ok({ accountGroup: accountGroup! });
|
|
203
143
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect, it
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { createMockDb } from "../../../testing/index";
|
|
3
3
|
import type { Transaction } from "../generated/kysely-tailordb";
|
|
4
4
|
import {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
NameRequiredError,
|
|
8
8
|
} from "../lib/errors.generated";
|
|
9
9
|
import { baseDraftCoa, baseActiveCoa, baseArchivedCoa } from "../testing/fixtures";
|
|
10
|
-
import { run
|
|
10
|
+
import { run } from "./updateChartOfAccounts";
|
|
11
11
|
import type { CommandContext } from "@tailor-platform/erp-kit/module";
|
|
12
12
|
|
|
13
13
|
const ctx: CommandContext = {
|
|
@@ -112,35 +112,6 @@ describe("updateChartOfAccounts", () => {
|
|
|
112
112
|
const setData = spies.set.mock.calls[0][0] as Record<string, unknown>;
|
|
113
113
|
expect(setData.customField).toBe("custom-value");
|
|
114
114
|
});
|
|
115
|
-
it("emits audit event recording previous and new field values", async () => {
|
|
116
|
-
const { db, spies } = createMockDb<Transaction>();
|
|
117
|
-
const updatedCoa = { ...baseDraftCoa, name: "Updated Name" };
|
|
118
|
-
spies.select.mockReturnValueOnce(baseDraftCoa);
|
|
119
|
-
spies.update.mockReturnValue(updatedCoa);
|
|
120
|
-
|
|
121
|
-
const mockLogAuditEvent = vi.fn().mockResolvedValue({ ok: true, value: {} });
|
|
122
|
-
const auditCommands: AuditCommands = { logAuditEvent: mockLogAuditEvent };
|
|
123
|
-
|
|
124
|
-
const result = await run(db, { id: baseDraftCoa.id, name: "Updated Name" }, ctx, auditCommands);
|
|
125
|
-
|
|
126
|
-
expect(result.ok).toBe(true);
|
|
127
|
-
expect(mockLogAuditEvent).toHaveBeenCalledWith(
|
|
128
|
-
db,
|
|
129
|
-
expect.objectContaining({
|
|
130
|
-
entityType: "ChartOfAccounts",
|
|
131
|
-
entityId: baseDraftCoa.id,
|
|
132
|
-
operationType: "UPDATE",
|
|
133
|
-
companyId: baseDraftCoa.companyId,
|
|
134
|
-
actorType: "USER",
|
|
135
|
-
actorId: ctx.actorId,
|
|
136
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
137
|
-
changes: expect.arrayContaining([
|
|
138
|
-
{ fieldName: "name", oldValue: baseDraftCoa.name, newValue: "Updated Name" },
|
|
139
|
-
]),
|
|
140
|
-
}),
|
|
141
|
-
ctx,
|
|
142
|
-
);
|
|
143
|
-
});
|
|
144
115
|
});
|
|
145
116
|
|
|
146
117
|
// Helper type for custom fields test
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import type { Transaction } from "../generated/kysely-tailordb";
|
|
3
2
|
import {
|
|
4
3
|
ChartOfAccountsNotFoundError,
|
|
@@ -13,22 +12,6 @@ export type UpdateChartOfAccountsInput = {
|
|
|
13
12
|
description?: string | null;
|
|
14
13
|
};
|
|
15
14
|
|
|
16
|
-
export interface AuditCommands {
|
|
17
|
-
logAuditEvent: (
|
|
18
|
-
db: Transaction,
|
|
19
|
-
input: {
|
|
20
|
-
eventId: string;
|
|
21
|
-
actorType: string;
|
|
22
|
-
actorId: string;
|
|
23
|
-
entityType: string;
|
|
24
|
-
entityId: string;
|
|
25
|
-
operationType: string;
|
|
26
|
-
companyId?: string;
|
|
27
|
-
changes: { fieldName: string; oldValue?: unknown; newValue?: unknown }[];
|
|
28
|
-
},
|
|
29
|
-
ctx: CommandContext,
|
|
30
|
-
) => Promise<{ ok: true; value: unknown }>;
|
|
31
|
-
}
|
|
32
15
|
/**
|
|
33
16
|
* Function: updateChartOfAccounts
|
|
34
17
|
*
|
|
@@ -38,8 +21,7 @@ export interface AuditCommands {
|
|
|
38
21
|
export async function run<CF extends Record<string, unknown>>(
|
|
39
22
|
db: Transaction,
|
|
40
23
|
input: UpdateChartOfAccountsInput & Omit<Partial<CF>, "status">,
|
|
41
|
-
|
|
42
|
-
auditCommands?: AuditCommands,
|
|
24
|
+
_ctx: CommandContext,
|
|
43
25
|
) {
|
|
44
26
|
const { id, name, description, ...customFields } = input;
|
|
45
27
|
|
|
@@ -97,36 +79,5 @@ export async function run<CF extends Record<string, unknown>>(
|
|
|
97
79
|
.returningAll()
|
|
98
80
|
.executeTakeFirst();
|
|
99
81
|
|
|
100
|
-
if (auditCommands) {
|
|
101
|
-
const changes: { fieldName: string; oldValue?: unknown; newValue?: unknown }[] = [];
|
|
102
|
-
if (name !== undefined && name !== existing.name) {
|
|
103
|
-
changes.push({ fieldName: "name", oldValue: existing.name, newValue: name });
|
|
104
|
-
}
|
|
105
|
-
if (description !== undefined && description !== existing.description) {
|
|
106
|
-
changes.push({
|
|
107
|
-
fieldName: "description",
|
|
108
|
-
oldValue: existing.description,
|
|
109
|
-
newValue: description,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (changes.length > 0) {
|
|
114
|
-
await auditCommands.logAuditEvent(
|
|
115
|
-
db,
|
|
116
|
-
{
|
|
117
|
-
eventId: randomUUID(),
|
|
118
|
-
actorType: "USER",
|
|
119
|
-
actorId: ctx.actorId,
|
|
120
|
-
entityType: "ChartOfAccounts",
|
|
121
|
-
entityId: id,
|
|
122
|
-
operationType: "UPDATE",
|
|
123
|
-
companyId: existing.companyId,
|
|
124
|
-
changes,
|
|
125
|
-
},
|
|
126
|
-
ctx,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
82
|
return ok({ chartOfAccounts: chartOfAccounts! });
|
|
132
83
|
}
|
|
@@ -11,7 +11,6 @@ activateAccount transitions a GL account from DRAFT to ACTIVE status, making it
|
|
|
11
11
|
- Target account must be in DRAFT status
|
|
12
12
|
- Activating an already ACTIVE account fails with an invalid state transition error
|
|
13
13
|
- Activating an INACTIVE account fails (use reactivateAccount instead)
|
|
14
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, CoA reference, account code, and status transition from DRAFT to ACTIVE
|
|
15
14
|
|
|
16
15
|
## Process Flow
|
|
17
16
|
|
|
@@ -24,8 +23,7 @@ flowchart TD
|
|
|
24
23
|
B2 -->|Yes| D{Status is DRAFT?}
|
|
25
24
|
D -->|No| E[Return error: invalid state transition]
|
|
26
25
|
D -->|Yes| F[Update status to ACTIVE]
|
|
27
|
-
F --> G[
|
|
28
|
-
G --> H[Return activated account]
|
|
26
|
+
F --> G[Return activated account]
|
|
29
27
|
```
|
|
30
28
|
|
|
31
29
|
## External Dependencies
|
|
@@ -46,4 +44,3 @@ flowchart TD
|
|
|
46
44
|
- returns error when account is already ACTIVE
|
|
47
45
|
- returns error when account is INACTIVE
|
|
48
46
|
- activates a DRAFT account
|
|
49
|
-
- emits audit event recording status transition from DRAFT to ACTIVE
|
|
@@ -10,7 +10,6 @@ activateChartOfAccounts transitions a Chart of Accounts from DRAFT to ACTIVE sta
|
|
|
10
10
|
- Target CoA must be in DRAFT status
|
|
11
11
|
- Activating an already ACTIVE or ARCHIVED CoA fails with an invalid state transition error
|
|
12
12
|
- Only one CoA per company can be in ACTIVE status; activating a second CoA for the same company fails with a uniqueness constraint error
|
|
13
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, and status transition from DRAFT to ACTIVE
|
|
14
13
|
|
|
15
14
|
## Process Flow
|
|
16
15
|
|
|
@@ -23,8 +22,7 @@ flowchart TD
|
|
|
23
22
|
D -->|Yes| F{Another ACTIVE CoA for same company?}
|
|
24
23
|
F -->|Yes| G[Return error: duplicate active CoA]
|
|
25
24
|
F -->|No| H[Update status to ACTIVE]
|
|
26
|
-
H --> I[
|
|
27
|
-
I --> J[Return activated CoA]
|
|
25
|
+
H --> I[Return activated CoA]
|
|
28
26
|
```
|
|
29
27
|
|
|
30
28
|
## External Dependencies
|
|
@@ -44,4 +42,3 @@ flowchart TD
|
|
|
44
42
|
- returns error when CoA is ARCHIVED
|
|
45
43
|
- returns error when another ACTIVE CoA exists for the same company
|
|
46
44
|
- activates a DRAFT CoA
|
|
47
|
-
- emits audit event recording status transition from DRAFT to ACTIVE
|
|
@@ -20,7 +20,6 @@ createAccount establishes a new GL account in DRAFT status within a Chart of Acc
|
|
|
20
20
|
- Account group, when provided, must belong to the same CoA and account code must fall within the group's number range (if defined)
|
|
21
21
|
- Parent CoA must exist and be in DRAFT or ACTIVE status
|
|
22
22
|
- Account is always created in DRAFT status
|
|
23
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, CoA reference, account code, classification, and initial field values
|
|
24
23
|
|
|
25
24
|
## Process Flow
|
|
26
25
|
|
|
@@ -41,8 +40,7 @@ flowchart TD
|
|
|
41
40
|
L -->|Yes| N{Reconciliation valid for classification?}
|
|
42
41
|
N -->|No| Q[Return error: reconciliation required]
|
|
43
42
|
N -->|Yes| O[Create account in DRAFT]
|
|
44
|
-
O --> P[
|
|
45
|
-
P --> Q[Return created account]
|
|
43
|
+
O --> P[Return created account]
|
|
46
44
|
```
|
|
47
45
|
|
|
48
46
|
## External Dependencies
|
|
@@ -90,5 +88,4 @@ flowchart TD
|
|
|
90
88
|
- returns error when reconciliation explicitly set to false for RECEIVABLE classification
|
|
91
89
|
- returns error when reconciliation explicitly set to false for PAYABLE classification
|
|
92
90
|
- returns error when reconciliation explicitly set to false for BANK_CASH classification
|
|
93
|
-
- emits audit event recording acting user, timestamp, CoA reference, account code, and classification
|
|
94
91
|
- passes custom fields through to insert
|
|
@@ -12,7 +12,6 @@ createAccountGroup establishes a new account group within a Chart of Accounts. G
|
|
|
12
12
|
- Parent group, when provided, must exist within the same CoA
|
|
13
13
|
- Account number range, when defined, requires both start and end to be provided together, must be a valid interval (start < end), and must not overlap with other groups' ranges within the CoA
|
|
14
14
|
- Sort order controls display sequence among sibling groups
|
|
15
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, CoA reference, group code, and initial field values
|
|
16
15
|
|
|
17
16
|
## Process Flow
|
|
18
17
|
|
|
@@ -31,13 +30,12 @@ flowchart TD
|
|
|
31
30
|
F -->|Yes| H{Number range valid and non-overlapping?}
|
|
32
31
|
H -->|No| I[Return error: invalid or overlapping range]
|
|
33
32
|
H -->|Yes| J[Create account group]
|
|
34
|
-
J --> K[
|
|
35
|
-
K --> L[Return created group]
|
|
33
|
+
J --> K[Return created group]
|
|
36
34
|
```
|
|
37
35
|
|
|
38
36
|
## External Dependencies
|
|
39
37
|
|
|
40
|
-
-
|
|
38
|
+
- None
|
|
41
39
|
|
|
42
40
|
## Error Scenarios
|
|
43
41
|
|
|
@@ -66,5 +64,4 @@ flowchart TD
|
|
|
66
64
|
- creates a child group with valid parent
|
|
67
65
|
- creates a group with account number range
|
|
68
66
|
- creates a group with sort order
|
|
69
|
-
- emits audit event recording acting user, timestamp, CoA reference, group code, and initial field values
|
|
70
67
|
- passes custom fields through to insert
|
|
@@ -17,7 +17,6 @@ createChartOfAccounts establishes a new Chart of Accounts container in DRAFT sta
|
|
|
17
17
|
- When `templateId` is provided, the command delegates template resolution to the template provider (external dependency). The provider must return the template's account groups and accounts. If no template provider is configured, templateId is rejected with TEMPLATE_PROVIDER_NOT_CONFIGURED
|
|
18
18
|
- When a valid template is resolved, the command copies the template's account groups (with numbering ranges) and GL accounts into the new CoA in DRAFT status
|
|
19
19
|
- Template-based creation is a convenience shortcut — all copied entities are fully mutable in DRAFT and can be modified before activation
|
|
20
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, initial field values, and whether the CoA was created from a template or blank
|
|
21
20
|
|
|
22
21
|
## Process Flow
|
|
23
22
|
|
|
@@ -35,9 +34,8 @@ flowchart TD
|
|
|
35
34
|
H -->|No| I[Return error: template not found]
|
|
36
35
|
H -->|Yes| J[Create CoA in DRAFT with template contents]
|
|
37
36
|
G -->|No| K[Create blank CoA in DRAFT]
|
|
38
|
-
J -->
|
|
39
|
-
K -->
|
|
40
|
-
L --> M[Return created CoA]
|
|
37
|
+
J --> K2[Return created CoA]
|
|
38
|
+
K --> K2
|
|
41
39
|
```
|
|
42
40
|
|
|
43
41
|
## External Dependencies
|
|
@@ -68,5 +66,3 @@ flowchart TD
|
|
|
68
66
|
- returns error when organizationQueries reports company not found
|
|
69
67
|
- creates blank CoA in DRAFT status with inherited base currency when no templateId is provided
|
|
70
68
|
- template-copied entities are mutable and can be modified before activation
|
|
71
|
-
- emits audit event recording acting user, timestamp, and initial field values
|
|
72
|
-
- audit event includes whether CoA was created from template or blank
|
|
@@ -14,7 +14,6 @@ deactivateAccount transitions a GL account from ACTIVE to INACTIVE status, preve
|
|
|
14
14
|
- Deactivation exposes a pre-deactivation hook for the GL module to block the transition when open balances exist
|
|
15
15
|
- Without a GL module integrated, deactivation proceeds without balance checks
|
|
16
16
|
- Successor account mapping is optional
|
|
17
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, CoA reference, account code, status transition from ACTIVE to INACTIVE, and successor mapping if provided
|
|
18
17
|
|
|
19
18
|
## Process Flow
|
|
20
19
|
|
|
@@ -35,8 +34,7 @@ flowchart TD
|
|
|
35
34
|
J -->|No| K[Return error: successor not active]
|
|
36
35
|
J -->|Yes| L[Map successor and set INACTIVE]
|
|
37
36
|
I -->|No| L[Set status to INACTIVE]
|
|
38
|
-
L --> M[
|
|
39
|
-
M --> N[Return deactivated account]
|
|
37
|
+
L --> M[Return deactivated account]
|
|
40
38
|
```
|
|
41
39
|
|
|
42
40
|
## External Dependencies
|
|
@@ -62,4 +60,3 @@ flowchart TD
|
|
|
62
60
|
- deactivates an ACTIVE account with successor mapping
|
|
63
61
|
- deactivates without balance check when GL hook is not registered
|
|
64
62
|
- returns error when GL hook reports open balances
|
|
65
|
-
- emits audit event recording status transition from ACTIVE to INACTIVE and successor mapping
|
|
@@ -11,7 +11,6 @@ deactivateChartOfAccounts transitions a Chart of Accounts from ACTIVE to ARCHIVE
|
|
|
11
11
|
- Deactivating a DRAFT or already ARCHIVED CoA fails with an invalid state transition error
|
|
12
12
|
- Archived CoA records and their accounts remain queryable for reporting and audit
|
|
13
13
|
- This is a one-way transition; reactivation from ARCHIVED is not permitted
|
|
14
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, and status transition from ACTIVE to ARCHIVED
|
|
15
14
|
|
|
16
15
|
## Process Flow
|
|
17
16
|
|
|
@@ -22,8 +21,7 @@ flowchart TD
|
|
|
22
21
|
B -->|Yes| D{Status is ACTIVE?}
|
|
23
22
|
D -->|No| E[Return error: invalid state transition]
|
|
24
23
|
D -->|Yes| F[Update status to ARCHIVED]
|
|
25
|
-
F --> G[
|
|
26
|
-
G --> H[Return archived CoA]
|
|
24
|
+
F --> G[Return archived CoA]
|
|
27
25
|
```
|
|
28
26
|
|
|
29
27
|
## External Dependencies
|
|
@@ -41,4 +39,3 @@ flowchart TD
|
|
|
41
39
|
- returns error when CoA is DRAFT
|
|
42
40
|
- returns error when CoA is already ARCHIVED
|
|
43
41
|
- archives an ACTIVE CoA
|
|
44
|
-
- emits audit event recording status transition from ACTIVE to ARCHIVED
|
|
@@ -11,7 +11,6 @@ deleteAccount permanently removes a GL account that is in DRAFT status and has n
|
|
|
11
11
|
- Target account must be in DRAFT status
|
|
12
12
|
- Target account must have no posted transactions
|
|
13
13
|
- Deleting ACTIVE or INACTIVE accounts is rejected
|
|
14
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, CoA reference, account code, and deletion
|
|
15
14
|
|
|
16
15
|
## Process Flow
|
|
17
16
|
|
|
@@ -26,8 +25,7 @@ flowchart TD
|
|
|
26
25
|
D -->|Yes| F{Has posted transactions?}
|
|
27
26
|
F -->|Yes| G[Return error: has posted transactions]
|
|
28
27
|
F -->|No| H[Delete account record]
|
|
29
|
-
H --> I[
|
|
30
|
-
I --> J[Return success]
|
|
28
|
+
H --> I[Return success]
|
|
31
29
|
```
|
|
32
30
|
|
|
33
31
|
## External Dependencies
|
|
@@ -49,4 +47,3 @@ flowchart TD
|
|
|
49
47
|
- returns error when account is INACTIVE
|
|
50
48
|
- returns error when DRAFT account has posted transactions
|
|
51
49
|
- deletes a DRAFT account with no posted transactions
|
|
52
|
-
- emits audit event recording deletion, acting user, and account code
|
|
@@ -10,7 +10,6 @@ deleteAccountGroup permanently removes an account group that has no child groups
|
|
|
10
10
|
- Parent CoA must be in DRAFT or ACTIVE status; deleting a group under an ARCHIVED CoA is rejected
|
|
11
11
|
- Group must have no child groups
|
|
12
12
|
- Group must have no accounts assigned to it
|
|
13
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, and deletion of the group
|
|
14
13
|
|
|
15
14
|
## Process Flow
|
|
16
15
|
|
|
@@ -25,8 +24,7 @@ flowchart TD
|
|
|
25
24
|
D -->|No| F{Has assigned accounts?}
|
|
26
25
|
F -->|Yes| G[Return error: has assigned accounts]
|
|
27
26
|
F -->|No| H[Delete group]
|
|
28
|
-
H --> I[
|
|
29
|
-
I --> J[Return success]
|
|
27
|
+
H --> I[Return success]
|
|
30
28
|
```
|
|
31
29
|
|
|
32
30
|
## External Dependencies
|
|
@@ -47,4 +45,3 @@ flowchart TD
|
|
|
47
45
|
- returns error when group has child groups
|
|
48
46
|
- returns error when group has assigned accounts
|
|
49
47
|
- deletes a leaf group with no assigned accounts
|
|
50
|
-
- emits audit event recording deletion and acting user
|
|
@@ -9,8 +9,6 @@ deleteChartOfAccounts permanently removes a Chart of Accounts that is still in D
|
|
|
9
9
|
- Target CoA must exist
|
|
10
10
|
- Target CoA must be in DRAFT status; deleting ACTIVE or ARCHIVED CoA is rejected
|
|
11
11
|
- Deletion cascade-deletes all child Account and AccountGroup records belonging to the CoA. Because only DRAFT CoA records can be deleted, and accounts can only be created under a DRAFT or ACTIVE CoA, all child accounts are guaranteed to be in DRAFT status with no posted transactions at this point — making cascade deletion safe and consistent with the account deletion invariant
|
|
12
|
-
- Each cascade-deleted child record (Account and AccountGroup) emits its own audit event, followed by the CoA deletion audit event
|
|
13
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, and deletion of the CoA
|
|
14
12
|
|
|
15
13
|
## Process Flow
|
|
16
14
|
|
|
@@ -23,8 +21,7 @@ flowchart TD
|
|
|
23
21
|
D -->|Yes| F[Cascade-delete all child Accounts]
|
|
24
22
|
F --> G[Cascade-delete all child AccountGroups]
|
|
25
23
|
G --> H[Delete CoA record]
|
|
26
|
-
H --> I[
|
|
27
|
-
I --> J[Return success]
|
|
24
|
+
H --> I[Return success]
|
|
28
25
|
```
|
|
29
26
|
|
|
30
27
|
## External Dependencies
|
|
@@ -44,5 +41,3 @@ flowchart TD
|
|
|
44
41
|
- deletes a DRAFT CoA with no child records
|
|
45
42
|
- deletes a DRAFT CoA and cascade-deletes all child Accounts
|
|
46
43
|
- deletes a DRAFT CoA and cascade-deletes all child AccountGroups
|
|
47
|
-
- emits audit events for each cascade-deleted Account and AccountGroup
|
|
48
|
-
- emits audit event recording CoA deletion and acting user
|
|
@@ -12,7 +12,6 @@ moveAccountGroup reparents an account group by changing its parent reference wit
|
|
|
12
12
|
- A group cannot be moved under itself or any of its descendants (circular reference prevention)
|
|
13
13
|
- All child groups and their account assignments are preserved during the move
|
|
14
14
|
- Group code and account assignments are unchanged by the move
|
|
15
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, previous parent reference, and new parent reference
|
|
16
15
|
|
|
17
16
|
## Process Flow
|
|
18
17
|
|
|
@@ -29,8 +28,7 @@ flowchart TD
|
|
|
29
28
|
G -->|Yes| H[Return error: circular reference]
|
|
30
29
|
G -->|No| I[Update parent reference]
|
|
31
30
|
D -->|No/null| I[Promote to root]
|
|
32
|
-
I --> J[
|
|
33
|
-
J --> K[Return moved group]
|
|
31
|
+
I --> J[Return moved group]
|
|
34
32
|
```
|
|
35
33
|
|
|
36
34
|
## External Dependencies
|
|
@@ -54,4 +52,3 @@ flowchart TD
|
|
|
54
52
|
- returns error when moving group under its descendant
|
|
55
53
|
- moves group to different parent
|
|
56
54
|
- promotes group to root by setting parent to null
|
|
57
|
-
- emits audit event recording previous and new parent references
|
|
@@ -11,7 +11,6 @@ reactivateAccount transitions a GL account from INACTIVE back to ACTIVE status,
|
|
|
11
11
|
- Target account must be in INACTIVE status
|
|
12
12
|
- Reactivating a DRAFT or ACTIVE account fails with an invalid state transition error
|
|
13
13
|
- Reactivation clears any previously mapped successor account
|
|
14
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, CoA reference, account code, and status transition from INACTIVE to ACTIVE
|
|
15
14
|
|
|
16
15
|
## Process Flow
|
|
17
16
|
|
|
@@ -25,8 +24,7 @@ flowchart TD
|
|
|
25
24
|
D -->|No| E[Return error: invalid state transition]
|
|
26
25
|
D -->|Yes| F[Clear successor mapping]
|
|
27
26
|
F --> G[Update status to ACTIVE]
|
|
28
|
-
G --> H[
|
|
29
|
-
H --> I[Return reactivated account]
|
|
27
|
+
G --> H[Return reactivated account]
|
|
30
28
|
```
|
|
31
29
|
|
|
32
30
|
## External Dependencies
|
|
@@ -47,4 +45,3 @@ flowchart TD
|
|
|
47
45
|
- returns error when account is already ACTIVE
|
|
48
46
|
- reactivates an INACTIVE account
|
|
49
47
|
- clears successor mapping on reactivation
|
|
50
|
-
- emits audit event recording status transition from INACTIVE to ACTIVE
|
|
@@ -19,7 +19,6 @@ updateAccount modifies attributes of an existing GL account. Structural fields (
|
|
|
19
19
|
- Currency restriction changes must reference a valid currency from the primitives module. An account with currency restriction only accepts postings in that currency (enforced by downstream posting modules)
|
|
20
20
|
- Account group changes must reference a group in the same CoA, and the account code must fall within the group's number range (if defined)
|
|
21
21
|
- When the account code is changed and the account belongs to an account group (whether the group assignment is also changing or staying the same), the new code must fall within the target group's number range (if defined). This applies to both cases: changing only the code while keeping the current group, and changing both the code and the group simultaneously
|
|
22
|
-
- Emits an audit event via the audit module recording the acting user, timestamp, CoA reference, account code, and previous and new field values for all changed attributes
|
|
23
22
|
|
|
24
23
|
## Process Flow
|
|
25
24
|
|
|
@@ -44,8 +43,7 @@ flowchart TD
|
|
|
44
43
|
H --> H2{Reconciliation invariant violated?}
|
|
45
44
|
H2 -->|Yes| H3[Return error: reconciliation required]
|
|
46
45
|
H2 -->|No| I[Update account fields]
|
|
47
|
-
I --> J[
|
|
48
|
-
J --> K[Return updated account]
|
|
46
|
+
I --> J[Return updated account]
|
|
49
47
|
```
|
|
50
48
|
|
|
51
49
|
## External Dependencies
|
|
@@ -98,5 +96,4 @@ flowchart TD
|
|
|
98
96
|
- returns error when changing code to a value outside the current group's number range
|
|
99
97
|
- returns error when changing classification from RECEIVABLE after posted transactions
|
|
100
98
|
- returns error when changing classification from PAYABLE after posted transactions
|
|
101
|
-
- emits audit event recording previous and new field values for all changed attributes
|
|
102
99
|
- passes custom fields through to update
|