@tailor-platform/erp-kit 0.1.2 → 0.2.1
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 +12 -0
- package/README.md +80 -12
- package/dist/cli.js +1070 -450
- package/package.json +11 -8
- package/schemas/app-compose/business-flow.yml +3 -0
- package/schemas/app-compose/story.yml +1 -1
- package/schemas/module/model.yml +5 -0
- package/skills/{app-compose-1-requirement-analysis → erp-kit-app-1-requirements}/SKILL.md +8 -14
- package/skills/{app-compose-2-requirements-breakdown → erp-kit-app-2-breakdown}/SKILL.md +6 -13
- package/skills/{app-compose-3-doc-review → erp-kit-app-3-doc-review}/SKILL.md +2 -6
- package/skills/{app-compose-6-implementation-spec → erp-kit-app-4-impl-spec}/SKILL.md +11 -22
- package/skills/erp-kit-app-5-implementation/SKILL.md +149 -0
- package/skills/erp-kit-app-5-implementation/references/backend.md +232 -0
- package/skills/erp-kit-app-5-implementation/references/frontend.md +242 -0
- package/skills/{mock-scenario → erp-kit-mock-scenario}/SKILL.md +1 -1
- package/skills/{1-module-docs → erp-kit-module-1-docs}/SKILL.md +2 -2
- package/skills/{2-module-feature-breakdown → erp-kit-module-2-feature-breakdown}/SKILL.md +13 -9
- package/skills/erp-kit-module-2-feature-breakdown/references/naming.md +59 -0
- package/skills/{3-module-doc-review → erp-kit-module-3-doc-review}/SKILL.md +83 -25
- package/skills/erp-kit-module-4-tdd/SKILL.md +94 -0
- package/skills/erp-kit-module-4-tdd/references/cross-module-dependency.md +133 -0
- package/skills/{4-module-tdd-implementation → erp-kit-module-4-tdd}/references/db-relations.md +5 -1
- package/skills/{4-module-tdd-implementation → erp-kit-module-4-tdd}/references/exports.md +1 -1
- package/skills/erp-kit-module-4-tdd/references/generated-code.md +32 -0
- package/skills/{5-module-implementation-review → erp-kit-module-5-impl-review}/SKILL.md +46 -44
- package/skills/erp-kit-module-5-impl-review/references/commands.md +62 -0
- package/skills/erp-kit-module-5-impl-review/references/errors.md +10 -0
- package/skills/{5-module-implementation-review → erp-kit-module-5-impl-review}/references/testing.md +1 -1
- package/skills/erp-kit-module-shared/SKILL.md +16 -0
- package/skills/erp-kit-module-shared/references/commands.md +203 -0
- package/skills/erp-kit-module-shared/references/errors.md +35 -0
- package/skills/erp-kit-module-shared/references/queries.md +168 -0
- package/skills/erp-kit-module-shared/references/structure.md +36 -0
- package/skills/{3-module-doc-review → erp-kit-module-shared}/references/testing.md +4 -3
- package/skills/erp-kit-update/SKILL.md +64 -0
- package/src/cli.doc.test.ts +65 -0
- package/src/cli.ts +3 -35
- package/src/commands/app/index.ts +3 -3
- package/src/commands/check.test.ts +1 -1
- package/src/commands/check.ts +2 -2
- package/src/commands/index.ts +73 -0
- package/src/commands/init.test.ts +22 -5
- package/src/commands/init.ts +25 -16
- package/src/commands/license.ts +193 -0
- package/src/commands/mock/index.ts +2 -2
- package/src/commands/mock/start.ts +1 -1
- package/src/commands/mock/validate.test.ts +1 -1
- package/src/commands/module/generate.ts +35 -0
- package/src/commands/module/index.ts +6 -4
- package/src/commands/module/list.test.ts +7 -12
- package/src/commands/module/list.ts +1 -1
- package/src/commands/scaffold-templates.ts +65 -0
- package/src/commands/scaffold.test.ts +92 -2
- package/src/commands/scaffold.ts +22 -2
- package/src/commands/sync-check.test.ts +60 -1
- package/src/commands/sync-check.ts +35 -2
- package/src/generator/generate-code.test.ts +200 -0
- package/src/generator/generate-code.ts +260 -0
- package/src/generator/parse-command-doc.test.ts +159 -0
- package/src/generator/parse-command-doc.ts +116 -0
- package/src/integration.test.ts +2 -2
- package/src/module.ts +44 -6
- package/src/modules/item-management/README.md +38 -0
- package/src/modules/item-management/command/activateItem.generated.ts +6 -0
- package/src/modules/item-management/command/activateItem.test.ts +76 -0
- package/src/modules/item-management/command/activateItem.ts +42 -0
- package/src/modules/item-management/command/assignItemToTaxonomy.generated.ts +6 -0
- package/src/modules/item-management/command/assignItemToTaxonomy.test.ts +88 -0
- package/src/modules/item-management/command/assignItemToTaxonomy.ts +63 -0
- package/src/modules/item-management/command/createItem.generated.ts +6 -0
- package/src/modules/item-management/command/createItem.test.ts +152 -0
- package/src/modules/item-management/command/createItem.ts +72 -0
- package/src/modules/item-management/command/createTaxonomyNode.generated.ts +6 -0
- package/src/modules/item-management/command/createTaxonomyNode.test.ts +126 -0
- package/src/modules/item-management/command/createTaxonomyNode.ts +70 -0
- package/src/modules/item-management/command/deactivateItem.generated.ts +6 -0
- package/src/modules/item-management/command/deactivateItem.test.ts +76 -0
- package/src/modules/item-management/command/deactivateItem.ts +42 -0
- package/src/modules/item-management/command/deleteItem.generated.ts +6 -0
- package/src/modules/item-management/command/deleteItem.test.ts +61 -0
- package/src/modules/item-management/command/deleteItem.ts +38 -0
- package/src/modules/item-management/command/deleteTaxonomyNode.generated.ts +6 -0
- package/src/modules/item-management/command/deleteTaxonomyNode.test.ts +73 -0
- package/src/modules/item-management/command/deleteTaxonomyNode.ts +50 -0
- package/src/modules/item-management/command/moveTaxonomyNode.generated.ts +6 -0
- package/src/modules/item-management/command/moveTaxonomyNode.test.ts +136 -0
- package/src/modules/item-management/command/moveTaxonomyNode.ts +85 -0
- package/src/modules/item-management/command/reactivateItem.generated.ts +6 -0
- package/src/modules/item-management/command/reactivateItem.test.ts +76 -0
- package/src/modules/item-management/command/reactivateItem.ts +42 -0
- package/src/modules/item-management/command/removeItemFromTaxonomy.generated.ts +6 -0
- package/src/modules/item-management/command/removeItemFromTaxonomy.test.ts +43 -0
- package/src/modules/item-management/command/removeItemFromTaxonomy.ts +30 -0
- package/src/modules/item-management/command/updateItem.generated.ts +6 -0
- package/src/modules/item-management/command/updateItem.test.ts +178 -0
- package/src/modules/item-management/command/updateItem.ts +103 -0
- package/src/modules/item-management/command/updateTaxonomyNode.generated.ts +6 -0
- package/src/modules/item-management/command/updateTaxonomyNode.test.ts +88 -0
- package/src/modules/item-management/command/updateTaxonomyNode.ts +62 -0
- package/src/modules/item-management/db/item.ts +47 -0
- package/src/modules/item-management/db/itemTaxonomyAssignment.ts +49 -0
- package/src/modules/item-management/db/taxonomyNode.ts +34 -0
- package/src/modules/item-management/docs/commands/ActivateItem.md +32 -0
- package/src/modules/item-management/docs/commands/AssignItemToTaxonomy.md +38 -0
- package/src/modules/item-management/docs/commands/CreateItem.md +44 -0
- package/src/modules/item-management/docs/commands/CreateTaxonomyNode.md +44 -0
- package/src/modules/item-management/docs/commands/DeactivateItem.md +34 -0
- package/src/modules/item-management/docs/commands/DeleteItem.md +35 -0
- package/src/modules/item-management/docs/commands/DeleteTaxonomyNode.md +39 -0
- package/src/modules/item-management/docs/commands/MoveTaxonomyNode.md +45 -0
- package/src/modules/item-management/docs/commands/ReactivateItem.md +34 -0
- package/src/modules/item-management/docs/commands/RemoveItemFromTaxonomy.md +30 -0
- package/src/modules/item-management/docs/commands/UpdateItem.md +55 -0
- package/src/modules/item-management/docs/commands/UpdateTaxonomyNode.md +36 -0
- package/src/modules/item-management/docs/features/item-lifecycle.md +60 -0
- package/src/modules/item-management/docs/features/item-taxonomy.md +65 -0
- package/src/modules/item-management/docs/models/ItemTaxonomyAssignment.md +36 -0
- package/src/modules/item-management/docs/models/TaxonomyNode.md +47 -0
- package/src/modules/item-management/docs/models/item.md +59 -0
- package/src/modules/item-management/docs/queries/CalculateNodeDepth.md +36 -0
- package/src/modules/item-management/docs/queries/CalculateSubtreeDepth.md +40 -0
- package/src/modules/item-management/docs/queries/DetectCircularReference.md +41 -0
- package/src/modules/item-management/docs/queries/GetItem.md +38 -0
- package/src/modules/item-management/docs/queries/GetItemTaxonomyAssignment.md +29 -0
- package/src/modules/item-management/docs/queries/GetTaxonomyNode.md +35 -0
- package/src/modules/item-management/docs/queries/GetTaxonomyNodeAssignments.md +29 -0
- package/src/modules/item-management/docs/queries/GetTaxonomyNodeChildren.md +29 -0
- package/src/modules/item-management/generated/enums.ts +9 -0
- package/src/modules/item-management/generated/kysely-tailordb.ts +62 -0
- package/src/modules/item-management/index.ts +53 -0
- package/src/modules/item-management/lib/_db_deps.ts +13 -0
- package/src/modules/item-management/lib/errors.generated.ts +117 -0
- package/src/modules/item-management/lib/permissions.generated.ts +17 -0
- package/src/modules/item-management/lib/types.ts +19 -0
- package/src/modules/item-management/module.ts +97 -0
- package/src/modules/item-management/query/calculateNodeDepth.generated.ts +5 -0
- package/src/modules/item-management/query/calculateNodeDepth.test.ts +56 -0
- package/src/modules/item-management/query/calculateNodeDepth.ts +28 -0
- package/src/modules/item-management/query/calculateSubtreeDepth.generated.ts +5 -0
- package/src/modules/item-management/query/calculateSubtreeDepth.test.ts +75 -0
- package/src/modules/item-management/query/calculateSubtreeDepth.ts +29 -0
- package/src/modules/item-management/query/detectCircularReference.generated.ts +5 -0
- package/src/modules/item-management/query/detectCircularReference.test.ts +61 -0
- package/src/modules/item-management/query/detectCircularReference.ts +32 -0
- package/src/modules/item-management/query/getItem.generated.ts +5 -0
- package/src/modules/item-management/query/getItem.test.ts +67 -0
- package/src/modules/item-management/query/getItem.ts +20 -0
- package/src/modules/item-management/query/getItemTaxonomyAssignment.generated.ts +5 -0
- package/src/modules/item-management/query/getItemTaxonomyAssignment.test.ts +25 -0
- package/src/modules/item-management/query/getItemTaxonomyAssignment.ts +18 -0
- package/src/modules/item-management/query/getTaxonomyNode.generated.ts +5 -0
- package/src/modules/item-management/query/getTaxonomyNode.test.ts +47 -0
- package/src/modules/item-management/query/getTaxonomyNode.ts +18 -0
- package/src/modules/item-management/query/getTaxonomyNodeAssignments.generated.ts +5 -0
- package/src/modules/item-management/query/getTaxonomyNodeAssignments.test.ts +25 -0
- package/src/modules/item-management/query/getTaxonomyNodeAssignments.ts +16 -0
- package/src/modules/item-management/query/getTaxonomyNodeChildren.generated.ts +5 -0
- package/src/modules/item-management/query/getTaxonomyNodeChildren.test.ts +34 -0
- package/src/modules/item-management/query/getTaxonomyNodeChildren.ts +16 -0
- package/src/modules/item-management/tailor.config.ts +11 -0
- package/src/modules/item-management/testing/fixtures.ts +81 -0
- package/src/modules/primitives/command/activateCategory.generated.ts +6 -0
- package/src/modules/primitives/command/activateCategory.test.ts +11 -29
- package/src/modules/primitives/command/activateCategory.ts +27 -34
- package/src/modules/primitives/command/activateCurrency.generated.ts +6 -0
- package/src/modules/primitives/command/activateCurrency.test.ts +11 -29
- package/src/modules/primitives/command/activateCurrency.ts +27 -34
- package/src/modules/primitives/command/activateUnit.generated.ts +6 -0
- package/src/modules/primitives/command/activateUnit.test.ts +11 -15
- package/src/modules/primitives/command/activateUnit.ts +27 -34
- package/src/modules/primitives/command/createCategory.generated.ts +6 -0
- package/src/modules/primitives/command/createCategory.test.ts +27 -39
- package/src/modules/primitives/command/createCategory.ts +53 -62
- package/src/modules/primitives/command/createCurrency.generated.ts +6 -0
- package/src/modules/primitives/command/createCurrency.test.ts +78 -71
- package/src/modules/primitives/command/createCurrency.ts +43 -48
- package/src/modules/primitives/command/createExchangeRate.generated.ts +6 -0
- package/src/modules/primitives/command/createExchangeRate.test.ts +101 -100
- package/src/modules/primitives/command/createExchangeRate.ts +50 -59
- package/src/modules/primitives/command/createUnit.generated.ts +6 -0
- package/src/modules/primitives/command/createUnit.test.ts +92 -95
- package/src/modules/primitives/command/createUnit.ts +54 -57
- package/src/modules/primitives/command/deactivateCategory.generated.ts +6 -0
- package/src/modules/primitives/command/deactivateCategory.test.ts +27 -28
- package/src/modules/primitives/command/deactivateCategory.ts +43 -50
- package/src/modules/primitives/command/deactivateCurrency.generated.ts +6 -0
- package/src/modules/primitives/command/deactivateCurrency.test.ts +23 -38
- package/src/modules/primitives/command/deactivateCurrency.ts +31 -38
- package/src/modules/primitives/command/deactivateUnit.generated.ts +6 -0
- package/src/modules/primitives/command/deactivateUnit.test.ts +27 -23
- package/src/modules/primitives/command/deactivateUnit.ts +39 -49
- package/src/modules/primitives/command/setBaseCurrency.generated.ts +6 -0
- package/src/modules/primitives/command/setBaseCurrency.test.ts +40 -33
- package/src/modules/primitives/command/setBaseCurrency.ts +43 -50
- package/src/modules/primitives/command/setReferenceUnit.generated.ts +6 -0
- package/src/modules/primitives/command/setReferenceUnit.test.ts +39 -35
- package/src/modules/primitives/command/setReferenceUnit.ts +46 -59
- package/src/modules/primitives/db/unit.ts +13 -3
- package/src/modules/primitives/docs/commands/ActivateCategory.md +1 -2
- package/src/modules/primitives/docs/commands/ActivateCurrency.md +1 -2
- package/src/modules/primitives/docs/commands/ActivateUnit.md +1 -2
- package/src/modules/primitives/docs/commands/CreateCategory.md +1 -4
- package/src/modules/primitives/docs/commands/CreateCurrency.md +3 -4
- package/src/modules/primitives/docs/commands/CreateExchangeRate.md +4 -5
- package/src/modules/primitives/docs/commands/CreateUnit.md +5 -5
- package/src/modules/primitives/docs/commands/DeactivateCategory.md +2 -3
- package/src/modules/primitives/docs/commands/DeactivateCurrency.md +2 -3
- package/src/modules/primitives/docs/commands/DeactivateUnit.md +2 -3
- package/src/modules/primitives/docs/commands/SetBaseCurrency.md +2 -3
- package/src/modules/primitives/docs/commands/SetReferenceUnit.md +2 -3
- package/src/modules/primitives/docs/queries/ConvertAmount.md +3 -5
- package/src/modules/primitives/docs/queries/ConvertQuantity.md +3 -5
- package/src/modules/primitives/docs/queries/GetBaseCurrency.md +32 -0
- package/src/modules/primitives/docs/queries/GetCurrency.md +36 -0
- package/src/modules/primitives/docs/queries/GetUnit.md +36 -0
- package/src/modules/primitives/docs/queries/GetUoMCategory.md +36 -0
- package/src/modules/primitives/docs/queries/ListUnitsByCategory.md +26 -0
- package/src/modules/primitives/generated/kysely-tailordb.ts +24 -45
- package/src/modules/primitives/index.ts +15 -4
- package/src/modules/primitives/lib/errors.generated.ts +112 -0
- package/src/modules/primitives/{permissions.ts → lib/permissions.generated.ts} +9 -8
- package/src/modules/primitives/module.ts +37 -27
- package/src/modules/primitives/query/convertAmount.generated.ts +5 -0
- package/src/modules/primitives/query/convertAmount.test.ts +2 -2
- package/src/modules/primitives/query/convertAmount.ts +27 -28
- package/src/modules/primitives/query/convertQuantity.generated.ts +5 -0
- package/src/modules/primitives/query/convertQuantity.test.ts +6 -2
- package/src/modules/primitives/query/convertQuantity.ts +49 -57
- package/src/modules/primitives/query/getBaseCurrency.generated.ts +5 -0
- package/src/modules/primitives/query/getBaseCurrency.test.ts +28 -0
- package/src/modules/primitives/query/getBaseCurrency.ts +16 -0
- package/src/modules/primitives/query/getCurrency.generated.ts +5 -0
- package/src/modules/primitives/query/getCurrency.test.ts +47 -0
- package/src/modules/primitives/query/getCurrency.ts +18 -0
- package/src/modules/primitives/query/getUnit.generated.ts +5 -0
- package/src/modules/primitives/query/getUnit.test.ts +47 -0
- package/src/modules/primitives/query/getUnit.ts +18 -0
- package/src/modules/primitives/query/getUoMCategory.generated.ts +5 -0
- package/src/modules/primitives/query/getUoMCategory.test.ts +47 -0
- package/src/modules/primitives/query/getUoMCategory.ts +18 -0
- package/src/modules/primitives/query/listUnitsByCategory.generated.ts +5 -0
- package/src/modules/primitives/query/listUnitsByCategory.ts +16 -0
- package/src/modules/primitives/tailor.config.ts +3 -3
- package/src/modules/shared/defineCommand.test.ts +23 -10
- package/src/modules/shared/defineCommand.ts +23 -10
- package/src/modules/shared/internal.ts +1 -0
- package/src/modules/shared/requirePermission.test.ts +22 -21
- package/src/modules/shared/requirePermission.ts +8 -2
- package/src/modules/shared/result.ts +12 -0
- package/src/modules/testing/index.ts +36 -11
- package/src/modules/user-management/command/activateUser.generated.ts +6 -0
- package/src/modules/user-management/command/activateUser.test.ts +27 -27
- package/src/modules/user-management/command/activateUser.ts +40 -48
- package/src/modules/user-management/command/assignPermissionToRole.generated.ts +6 -0
- package/src/modules/user-management/command/assignPermissionToRole.test.ts +42 -43
- package/src/modules/user-management/command/assignPermissionToRole.ts +59 -62
- package/src/modules/user-management/command/assignRoleToUser.generated.ts +6 -0
- package/src/modules/user-management/command/assignRoleToUser.test.ts +70 -63
- package/src/modules/user-management/command/assignRoleToUser.ts +63 -66
- package/src/modules/user-management/command/createPermission.generated.ts +6 -0
- package/src/modules/user-management/command/createPermission.test.ts +45 -38
- package/src/modules/user-management/command/createPermission.ts +42 -46
- package/src/modules/user-management/command/createRole.generated.ts +6 -0
- package/src/modules/user-management/command/createRole.test.ts +30 -29
- package/src/modules/user-management/command/createRole.ts +33 -33
- package/src/modules/user-management/command/createUser.generated.ts +6 -0
- package/src/modules/user-management/command/createUser.test.ts +64 -42
- package/src/modules/user-management/command/createUser.ts +54 -56
- package/src/modules/user-management/command/deactivateUser.generated.ts +6 -0
- package/src/modules/user-management/command/deactivateUser.test.ts +27 -27
- package/src/modules/user-management/command/deactivateUser.ts +40 -48
- package/src/modules/user-management/command/logAuditEvent.generated.ts +6 -0
- package/src/modules/user-management/command/logAuditEvent.test.ts +50 -42
- package/src/modules/user-management/command/logAuditEvent.ts +25 -28
- package/src/modules/user-management/command/reactivateUser.generated.ts +6 -0
- package/src/modules/user-management/command/reactivateUser.test.ts +31 -27
- package/src/modules/user-management/command/reactivateUser.ts +40 -48
- package/src/modules/user-management/command/revokePermissionFromRole.generated.ts +6 -0
- package/src/modules/user-management/command/revokePermissionFromRole.test.ts +52 -51
- package/src/modules/user-management/command/revokePermissionFromRole.ts +60 -57
- package/src/modules/user-management/command/revokeRoleFromUser.generated.ts +6 -0
- package/src/modules/user-management/command/revokeRoleFromUser.test.ts +53 -48
- package/src/modules/user-management/command/revokeRoleFromUser.ts +58 -57
- package/src/modules/user-management/docs/commands/CreatePermission.md +2 -2
- package/src/modules/user-management/docs/commands/CreateRole.md +1 -1
- package/src/modules/user-management/generated/enums.ts +11 -11
- package/src/modules/user-management/generated/kysely-tailordb.ts +27 -56
- package/src/modules/user-management/index.ts +2 -2
- package/src/modules/user-management/lib/errors.generated.ts +67 -0
- package/src/modules/user-management/{permissions.ts → lib/permissions.generated.ts} +8 -7
- package/src/modules/user-management/module.ts +22 -22
- package/src/modules/user-management/tailor.config.ts +3 -3
- package/src/schemas.ts +1 -1
- package/skills/1-module-docs/references/structure.md +0 -22
- package/skills/2-module-feature-breakdown/references/commands.md +0 -48
- package/skills/2-module-feature-breakdown/references/structure.md +0 -22
- package/skills/3-module-doc-review/references/commands.md +0 -54
- package/skills/3-module-doc-review/references/models.md +0 -29
- package/skills/4-module-tdd-implementation/SKILL.md +0 -74
- package/skills/4-module-tdd-implementation/references/commands.md +0 -45
- package/skills/4-module-tdd-implementation/references/errors.md +0 -7
- package/skills/4-module-tdd-implementation/references/models.md +0 -30
- package/skills/4-module-tdd-implementation/references/structure.md +0 -22
- package/skills/4-module-tdd-implementation/references/testing.md +0 -37
- package/skills/5-module-implementation-review/references/commands.md +0 -45
- package/skills/5-module-implementation-review/references/errors.md +0 -7
- package/skills/5-module-implementation-review/references/exports.md +0 -8
- package/skills/5-module-implementation-review/references/models.md +0 -30
- package/skills/app-compose-1-requirement-analysis/references/structure.md +0 -27
- package/skills/app-compose-2-requirements-breakdown/references/screen-detailview.md +0 -106
- package/skills/app-compose-2-requirements-breakdown/references/screen-form.md +0 -139
- package/skills/app-compose-2-requirements-breakdown/references/screen-listview.md +0 -153
- package/skills/app-compose-2-requirements-breakdown/references/structure.md +0 -27
- package/skills/app-compose-3-doc-review/references/structure.md +0 -27
- package/skills/app-compose-4-design-mock/SKILL.md +0 -256
- package/skills/app-compose-4-design-mock/references/component.md +0 -50
- package/skills/app-compose-4-design-mock/references/screen-detailview.md +0 -106
- package/skills/app-compose-4-design-mock/references/screen-form.md +0 -139
- package/skills/app-compose-4-design-mock/references/screen-listview.md +0 -153
- package/skills/app-compose-4-design-mock/references/structure.md +0 -27
- package/skills/app-compose-5-design-mock-review/SKILL.md +0 -290
- package/skills/app-compose-5-design-mock-review/references/component.md +0 -50
- package/skills/app-compose-5-design-mock-review/references/screen-detailview.md +0 -106
- package/skills/app-compose-5-design-mock-review/references/screen-form.md +0 -139
- package/skills/app-compose-5-design-mock-review/references/screen-listview.md +0 -153
- package/skills/app-compose-6-implementation-spec/references/auth.md +0 -72
- package/skills/app-compose-6-implementation-spec/references/structure.md +0 -27
- package/src/modules/primitives/lib/errors.ts +0 -138
- package/src/modules/user-management/lib/errors.ts +0 -81
- /package/skills/{2-module-feature-breakdown → erp-kit-module-4-tdd}/references/models.md +0 -0
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type
|
|
5
|
-
type
|
|
6
|
-
type
|
|
7
|
-
type
|
|
8
|
-
type
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
type Generated<T> =
|
|
14
|
-
T extends ColumnType<infer S, infer I, infer U>
|
|
15
|
-
? ColumnType<S, I | undefined, U>
|
|
16
|
-
: ColumnType<T, T | undefined, T>;
|
|
2
|
+
createGetDB,
|
|
3
|
+
type Generated,
|
|
4
|
+
type Timestamp,
|
|
5
|
+
type NamespaceDB,
|
|
6
|
+
type NamespaceInsertable,
|
|
7
|
+
type NamespaceSelectable,
|
|
8
|
+
type NamespaceTable,
|
|
9
|
+
type NamespaceTableName,
|
|
10
|
+
type NamespaceTransaction,
|
|
11
|
+
type NamespaceUpdateable,
|
|
12
|
+
} from "@tailor-platform/sdk/kysely";
|
|
17
13
|
|
|
18
14
|
export interface Namespace {
|
|
19
15
|
"main-db": {
|
|
@@ -27,7 +23,7 @@ export interface Namespace {
|
|
|
27
23
|
isActive: boolean;
|
|
28
24
|
createdAt: Generated<Timestamp>;
|
|
29
25
|
updatedAt: Timestamp | null;
|
|
30
|
-
}
|
|
26
|
+
}
|
|
31
27
|
|
|
32
28
|
ExchangeRate: {
|
|
33
29
|
id: Generated<string>;
|
|
@@ -37,7 +33,7 @@ export interface Namespace {
|
|
|
37
33
|
effectiveDate: Timestamp;
|
|
38
34
|
createdAt: Generated<Timestamp>;
|
|
39
35
|
updatedAt: Timestamp | null;
|
|
40
|
-
}
|
|
36
|
+
}
|
|
41
37
|
|
|
42
38
|
Unit: {
|
|
43
39
|
id: Generated<string>;
|
|
@@ -49,7 +45,7 @@ export interface Namespace {
|
|
|
49
45
|
isActive: boolean;
|
|
50
46
|
createdAt: Generated<Timestamp>;
|
|
51
47
|
updatedAt: Timestamp | null;
|
|
52
|
-
}
|
|
48
|
+
}
|
|
53
49
|
|
|
54
50
|
UoMCategory: {
|
|
55
51
|
id: Generated<string>;
|
|
@@ -59,37 +55,20 @@ export interface Namespace {
|
|
|
59
55
|
isActive: boolean;
|
|
60
56
|
createdAt: Generated<Timestamp>;
|
|
61
57
|
updatedAt: Timestamp | null;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
export
|
|
67
|
-
namespace: N,
|
|
68
|
-
kyselyConfig?: Omit<KyselyConfig, "dialect">,
|
|
69
|
-
): Kysely<Namespace[N]> {
|
|
70
|
-
const client = new tailordb.Client({ namespace });
|
|
71
|
-
return new Kysely<Namespace[N]>({
|
|
72
|
-
dialect: new TailordbDialect(client),
|
|
73
|
-
...kyselyConfig,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
62
|
+
export const getDB = createGetDB<Namespace>();
|
|
76
63
|
|
|
77
|
-
export type DB<N extends keyof Namespace = keyof Namespace> =
|
|
64
|
+
export type DB<N extends keyof Namespace = keyof Namespace> = NamespaceDB<Namespace, N>;
|
|
78
65
|
|
|
79
66
|
export type Transaction<K extends keyof Namespace | DB = keyof Namespace> =
|
|
80
|
-
|
|
81
|
-
? KyselyTransaction<Namespace[N]>
|
|
82
|
-
: K extends keyof Namespace
|
|
83
|
-
? KyselyTransaction<Namespace[K]>
|
|
84
|
-
: never;
|
|
67
|
+
NamespaceTransaction<Namespace, K>;
|
|
85
68
|
|
|
86
|
-
type TableName =
|
|
87
|
-
|
|
88
|
-
}[keyof Namespace];
|
|
89
|
-
export type Table<T extends TableName> = {
|
|
90
|
-
[N in keyof Namespace]: T extends keyof Namespace[N] ? Namespace[N][T] : never;
|
|
91
|
-
}[keyof Namespace];
|
|
69
|
+
type TableName = NamespaceTableName<Namespace>;
|
|
70
|
+
export type Table<T extends TableName> = NamespaceTable<Namespace, T>;
|
|
92
71
|
|
|
93
|
-
export type Insertable<T extends
|
|
94
|
-
export type Selectable<T extends
|
|
95
|
-
export type Updateable<T extends
|
|
72
|
+
export type Insertable<T extends TableName> = NamespaceInsertable<Namespace, T>;
|
|
73
|
+
export type Selectable<T extends TableName> = NamespaceSelectable<Namespace, T>;
|
|
74
|
+
export type Updateable<T extends TableName> = NamespaceUpdateable<Namespace, T>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { defineModule } from "./module";
|
|
2
|
-
export { permissions, own, all } from "./permissions";
|
|
2
|
+
export { permissions, own, all } from "./lib/permissions.generated";
|
|
3
3
|
|
|
4
4
|
// errors
|
|
5
5
|
export {
|
|
6
|
-
|
|
6
|
+
UomCategoryNotFoundError,
|
|
7
7
|
UnitNotFoundError,
|
|
8
8
|
IncompatibleUnitsError,
|
|
9
9
|
InactiveUnitError,
|
|
@@ -18,16 +18,27 @@ export {
|
|
|
18
18
|
DuplicateCategoryNameError,
|
|
19
19
|
CategoryHasActiveUnitsError,
|
|
20
20
|
UnitNotInCategoryError,
|
|
21
|
-
|
|
21
|
+
InvalidIsoCodeError,
|
|
22
22
|
DuplicateCurrencyCodeError,
|
|
23
23
|
InvalidDecimalPlacesError,
|
|
24
24
|
CannotDeactivateBaseCurrencyError,
|
|
25
25
|
CannotSetInactiveAsBaseCurrencyError,
|
|
26
26
|
SameCurrencyPairError,
|
|
27
27
|
InvalidExchangeRateError,
|
|
28
|
-
} from "./lib/errors";
|
|
28
|
+
} from "./lib/errors.generated";
|
|
29
|
+
|
|
30
|
+
// queries
|
|
31
|
+
export { getUnit } from "./query/getUnit.generated";
|
|
32
|
+
export { getCurrency } from "./query/getCurrency.generated";
|
|
33
|
+
export { getUoMCategory } from "./query/getUoMCategory.generated";
|
|
34
|
+
export { getBaseCurrency } from "./query/getBaseCurrency.generated";
|
|
35
|
+
export { listUnitsByCategory } from "./query/listUnitsByCategory.generated";
|
|
29
36
|
|
|
30
37
|
// input types
|
|
38
|
+
export { type GetUnitInput } from "./query/getUnit";
|
|
39
|
+
export { type GetCurrencyInput } from "./query/getCurrency";
|
|
40
|
+
export { type GetUoMCategoryInput } from "./query/getUoMCategory";
|
|
41
|
+
export { type ListUnitsByCategoryInput } from "./query/listUnitsByCategory";
|
|
31
42
|
export { type ConvertQuantityInput } from "./query/convertQuantity";
|
|
32
43
|
export { type ActivateCategoryInput } from "./command/activateCategory";
|
|
33
44
|
export { type DeactivateCategoryInput } from "./command/deactivateCategory";
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// @generated — do not edit
|
|
2
|
+
import { createDomainError } from "../../shared/internal";
|
|
3
|
+
|
|
4
|
+
export const UomCategoryNotFoundError = createDomainError(
|
|
5
|
+
"UomCategoryNotFoundError", "UOM_CATEGORY_NOT_FOUND",
|
|
6
|
+
(identifier: string) => `Specified category ID does not exist: ${identifier}`,
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export const CurrencyNotFoundError = createDomainError(
|
|
10
|
+
"CurrencyNotFoundError", "CURRENCY_NOT_FOUND",
|
|
11
|
+
(identifier: string) => `Specified currency ID does not exist: ${identifier}`,
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export const UnitNotFoundError = createDomainError(
|
|
15
|
+
"UnitNotFoundError", "UNIT_NOT_FOUND",
|
|
16
|
+
(identifier: string) => `Specified unit ID does not exist: ${identifier}`,
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const DuplicateCategoryNameError = createDomainError(
|
|
20
|
+
"DuplicateCategoryNameError", "DUPLICATE_CATEGORY_NAME",
|
|
21
|
+
(identifier: string) => `Category with same name already exists: ${identifier}`,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const InvalidIsoCodeError = createDomainError(
|
|
25
|
+
"InvalidIsoCodeError", "INVALID_ISO_CODE",
|
|
26
|
+
(identifier: string) => `Code is not exactly 3 uppercase letters: ${identifier}`,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const DuplicateCurrencyCodeError = createDomainError(
|
|
30
|
+
"DuplicateCurrencyCodeError", "DUPLICATE_CURRENCY_CODE",
|
|
31
|
+
(identifier: string) => `Currency with same code already exists: ${identifier}`,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const InvalidDecimalPlacesError = createDomainError(
|
|
35
|
+
"InvalidDecimalPlacesError", "INVALID_DECIMAL_PLACES",
|
|
36
|
+
(identifier: string) => `Value is negative or exceeds maximum (typically 4): ${identifier}`,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export const InactiveCurrencyError = createDomainError(
|
|
40
|
+
"InactiveCurrencyError", "INACTIVE_CURRENCY",
|
|
41
|
+
(identifier: string) => `Source or target currency is inactive: ${identifier}`,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const SameCurrencyPairError = createDomainError(
|
|
45
|
+
"SameCurrencyPairError", "SAME_CURRENCY_PAIR",
|
|
46
|
+
(identifier: string) => `Source and target currencies are the same: ${identifier}`,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
export const InvalidExchangeRateError = createDomainError(
|
|
50
|
+
"InvalidExchangeRateError", "INVALID_EXCHANGE_RATE",
|
|
51
|
+
(identifier: string) => `Rate is zero, negative, or not a valid number: ${identifier}`,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export const CategoryNotActiveError = createDomainError(
|
|
55
|
+
"CategoryNotActiveError", "CATEGORY_NOT_ACTIVE",
|
|
56
|
+
(identifier: string) => `Category is inactive: ${identifier}`,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export const DuplicateUnitSymbolError = createDomainError(
|
|
60
|
+
"DuplicateUnitSymbolError", "DUPLICATE_UNIT_SYMBOL",
|
|
61
|
+
(identifier: string) => `Unit with same symbol already exists in category: ${identifier}`,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export const InvalidConversionFactorError = createDomainError(
|
|
65
|
+
"InvalidConversionFactorError", "INVALID_CONVERSION_FACTOR",
|
|
66
|
+
(identifier: string) => `Factor is zero, negative, or not a valid number: ${identifier}`,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export const InvalidRoundingPrecisionError = createDomainError(
|
|
70
|
+
"InvalidRoundingPrecisionError", "INVALID_ROUNDING_PRECISION",
|
|
71
|
+
(identifier: string) => `Precision is negative: ${identifier}`,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
export const CategoryHasActiveUnitsError = createDomainError(
|
|
75
|
+
"CategoryHasActiveUnitsError", "CATEGORY_HAS_ACTIVE_UNITS",
|
|
76
|
+
(identifier: string) => `Category still contains active units that must be deactivated first: ${identifier}`,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
export const CannotDeactivateBaseCurrencyError = createDomainError(
|
|
80
|
+
"CannotDeactivateBaseCurrencyError", "CANNOT_DEACTIVATE_BASE_CURRENCY",
|
|
81
|
+
(identifier: string) => `Attempting to deactivate the base currency, must change base currency first: ${identifier}`,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
export const CannotDeactivateReferenceUnitError = createDomainError(
|
|
85
|
+
"CannotDeactivateReferenceUnitError", "CANNOT_DEACTIVATE_REFERENCE_UNIT",
|
|
86
|
+
(identifier: string) => `Attempting to deactivate the category's reference unit, must change reference unit first: ${identifier}`,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
export const CannotSetInactiveAsBaseCurrencyError = createDomainError(
|
|
90
|
+
"CannotSetInactiveAsBaseCurrencyError", "CANNOT_SET_INACTIVE_AS_BASE_CURRENCY",
|
|
91
|
+
(identifier: string) => `Target currency is not in Active status, must be activated first: ${identifier}`,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
export const UnitNotInCategoryError = createDomainError(
|
|
95
|
+
"UnitNotInCategoryError", "UNIT_NOT_IN_CATEGORY",
|
|
96
|
+
(identifier: string) => `Unit belongs to a different category than specified: ${identifier}`,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
export const ExchangeRateNotFoundError = createDomainError(
|
|
100
|
+
"ExchangeRateNotFoundError", "EXCHANGE_RATE_NOT_FOUND",
|
|
101
|
+
(identifier: string) => `No rate found for the currency pair on or before the specified date: ${identifier}`,
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
export const IncompatibleUnitsError = createDomainError(
|
|
105
|
+
"IncompatibleUnitsError", "INCOMPATIBLE_UNITS",
|
|
106
|
+
(identifier: string) => `Source and target units belong to different categories: ${identifier}`,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
export const InactiveUnitError = createDomainError(
|
|
110
|
+
"InactiveUnitError", "INACTIVE_UNIT",
|
|
111
|
+
(identifier: string) => `Either source or target unit is inactive: ${identifier}`,
|
|
112
|
+
);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
// @generated — do not edit
|
|
2
|
+
import { definePermissions } from "../../shared/internal";
|
|
2
3
|
|
|
3
4
|
export const { permissions, own, all } = definePermissions("primitives", [
|
|
4
|
-
"createCategory",
|
|
5
5
|
"activateCategory",
|
|
6
|
-
"
|
|
7
|
-
"setReferenceUnit",
|
|
8
|
-
"createUnit",
|
|
6
|
+
"activateCurrency",
|
|
9
7
|
"activateUnit",
|
|
10
|
-
"
|
|
8
|
+
"createCategory",
|
|
11
9
|
"createCurrency",
|
|
12
|
-
"
|
|
10
|
+
"createExchangeRate",
|
|
11
|
+
"createUnit",
|
|
12
|
+
"deactivateCategory",
|
|
13
13
|
"deactivateCurrency",
|
|
14
|
+
"deactivateUnit",
|
|
14
15
|
"setBaseCurrency",
|
|
15
|
-
"
|
|
16
|
+
"setReferenceUnit",
|
|
16
17
|
] as const);
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { type TailorAnyDBField } from "@tailor-platform/sdk";
|
|
2
2
|
import { type EmptyFields, type FieldsToInsertable } from "../shared/internal";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { activateCategory } from "./command/activateCategory";
|
|
8
|
-
import { deactivateCategory } from "./command/deactivateCategory";
|
|
9
|
-
import { activateUnit } from "./command/activateUnit";
|
|
10
|
-
import { deactivateUnit } from "./command/deactivateUnit";
|
|
11
|
-
import { setReferenceUnit } from "./command/setReferenceUnit";
|
|
12
|
-
import { convertQuantity } from "./query/convertQuantity";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
3
|
+
import { createCategory } from "./command/createCategory.generated";
|
|
4
|
+
import { createCurrency } from "./command/createCurrency.generated";
|
|
5
|
+
import { createUnit } from "./command/createUnit.generated";
|
|
6
|
+
import { createExchangeRate } from "./command/createExchangeRate.generated";
|
|
7
|
+
import { activateCategory } from "./command/activateCategory.generated";
|
|
8
|
+
import { deactivateCategory } from "./command/deactivateCategory.generated";
|
|
9
|
+
import { activateUnit } from "./command/activateUnit.generated";
|
|
10
|
+
import { deactivateUnit } from "./command/deactivateUnit.generated";
|
|
11
|
+
import { setReferenceUnit } from "./command/setReferenceUnit.generated";
|
|
12
|
+
import { convertQuantity } from "./query/convertQuantity.generated";
|
|
13
|
+
import { getUnit } from "./query/getUnit.generated";
|
|
14
|
+
import { getCurrency } from "./query/getCurrency.generated";
|
|
15
|
+
import { getUoMCategory } from "./query/getUoMCategory.generated";
|
|
16
|
+
import { getBaseCurrency } from "./query/getBaseCurrency.generated";
|
|
17
|
+
import { listUnitsByCategory } from "./query/listUnitsByCategory.generated";
|
|
18
|
+
import { activateCurrency } from "./command/activateCurrency.generated";
|
|
19
|
+
import { deactivateCurrency } from "./command/deactivateCurrency.generated";
|
|
20
|
+
import { setBaseCurrency } from "./command/setBaseCurrency.generated";
|
|
21
|
+
import { convertAmount } from "./query/convertAmount.generated";
|
|
17
22
|
import { createUoMCategoryType, CreateUoMCategoryTypeParams } from "./db/uomCategory";
|
|
18
23
|
import { createUnitType, CreateUnitTypeParams } from "./db/unit";
|
|
19
24
|
import { createCurrencyType, CreateCurrencyTypeParams } from "./db/currency";
|
|
@@ -40,27 +45,32 @@ export const defineModule = <
|
|
|
40
45
|
params: DefineModuleParams<CatF, UnitF, CurF, ERF>,
|
|
41
46
|
) => {
|
|
42
47
|
const uomCategory = createUoMCategoryType(params.uomCategory ?? {});
|
|
43
|
-
const unit = createUnitType(params.unit
|
|
48
|
+
const unit = createUnitType({ ...params.unit, uomCategoryType: uomCategory });
|
|
44
49
|
const currency = createCurrencyType(params.currency ?? {});
|
|
45
50
|
const exchangeRate = createExchangeRateType(params.exchangeRate ?? {});
|
|
46
51
|
|
|
47
52
|
return {
|
|
48
53
|
db: { uomCategory, unit, currency, exchangeRate },
|
|
49
54
|
commands: {
|
|
50
|
-
createCategory:
|
|
51
|
-
createCurrency:
|
|
52
|
-
createUnit:
|
|
53
|
-
createExchangeRate:
|
|
54
|
-
activateCategory,
|
|
55
|
-
deactivateCategory,
|
|
56
|
-
activateUnit,
|
|
57
|
-
deactivateUnit,
|
|
58
|
-
setReferenceUnit,
|
|
59
|
-
activateCurrency,
|
|
60
|
-
deactivateCurrency,
|
|
61
|
-
setBaseCurrency,
|
|
55
|
+
createCategory: createCategory<FieldsToInsertable<CatF>, FieldsToInsertable<UnitF>>(),
|
|
56
|
+
createCurrency: createCurrency<FieldsToInsertable<CurF>>(),
|
|
57
|
+
createUnit: createUnit<FieldsToInsertable<UnitF>>(),
|
|
58
|
+
createExchangeRate: createExchangeRate<FieldsToInsertable<ERF>>(),
|
|
59
|
+
activateCategory: activateCategory(),
|
|
60
|
+
deactivateCategory: deactivateCategory(),
|
|
61
|
+
activateUnit: activateUnit(),
|
|
62
|
+
deactivateUnit: deactivateUnit(),
|
|
63
|
+
setReferenceUnit: setReferenceUnit(),
|
|
64
|
+
activateCurrency: activateCurrency(),
|
|
65
|
+
deactivateCurrency: deactivateCurrency(),
|
|
66
|
+
setBaseCurrency: setBaseCurrency(),
|
|
62
67
|
},
|
|
63
68
|
queries: {
|
|
69
|
+
getUnit,
|
|
70
|
+
getCurrency,
|
|
71
|
+
getUoMCategory,
|
|
72
|
+
getBaseCurrency,
|
|
73
|
+
listUnitsByCategory,
|
|
64
74
|
convertQuantity,
|
|
65
75
|
convertAmount,
|
|
66
76
|
},
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
CurrencyNotFoundError,
|
|
7
7
|
ExchangeRateNotFoundError,
|
|
8
8
|
InactiveCurrencyError,
|
|
9
|
-
} from "../lib/errors";
|
|
9
|
+
} from "../lib/errors.generated";
|
|
10
10
|
import {
|
|
11
11
|
baseCurrencyEUR,
|
|
12
12
|
baseCurrencyJPY,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
inactiveCurrency,
|
|
17
17
|
olderExchangeRateUSDtoEUR,
|
|
18
18
|
} from "../testing/fixtures";
|
|
19
|
-
import { convertAmount } from "./convertAmount";
|
|
19
|
+
import { convertAmount } from "./convertAmount.generated";
|
|
20
20
|
|
|
21
21
|
describe("convertAmount", () => {
|
|
22
22
|
const ctx: QueryContext = { actorId: "test-actor" };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ReadonlyDB, QueryContext } from "../../shared/internal";
|
|
2
2
|
import type { DB } from "../generated/kysely-tailordb";
|
|
3
3
|
import {
|
|
4
4
|
CurrencyNotFoundError,
|
|
5
5
|
ExchangeRateNotFoundError,
|
|
6
6
|
InactiveCurrencyError,
|
|
7
|
-
} from "../lib/errors";
|
|
7
|
+
} from "../lib/errors.generated";
|
|
8
|
+
import { getCurrency } from "./getCurrency.generated";
|
|
8
9
|
|
|
9
10
|
export interface ConvertAmountInput {
|
|
10
11
|
amount: number;
|
|
@@ -14,38 +15,40 @@ export interface ConvertAmountInput {
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* Function: convertAmount
|
|
18
|
-
*
|
|
19
18
|
* Converts a monetary amount from one currency to another using the applicable
|
|
20
19
|
* exchange rate for a given date. Currencies are identified by their ISO 4217
|
|
21
20
|
* code (e.g., "USD", "EUR", "JPY"). The function looks up the most recent exchange
|
|
22
21
|
* rate on or before the specified date. If no direct rate exists, it calculates
|
|
23
22
|
* the inverse rate. Result is rounded to the target currency's decimal precision.
|
|
24
23
|
*/
|
|
25
|
-
export
|
|
26
|
-
//
|
|
27
|
-
const sourceCurrency = await
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
export async function run(db: ReadonlyDB<DB>, input: ConvertAmountInput, ctx: QueryContext) {
|
|
25
|
+
// Validate source currency exists
|
|
26
|
+
const { currency: sourceCurrency } = await getCurrency(
|
|
27
|
+
db,
|
|
28
|
+
{
|
|
29
|
+
code: input.sourceCurrencyCode,
|
|
30
|
+
},
|
|
31
|
+
ctx,
|
|
32
|
+
);
|
|
32
33
|
|
|
33
34
|
if (!sourceCurrency) {
|
|
34
35
|
throw new CurrencyNotFoundError(input.sourceCurrencyCode);
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
-
const targetCurrency = await
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
// Validate target currency exists
|
|
39
|
+
const { currency: targetCurrency } = await getCurrency(
|
|
40
|
+
db,
|
|
41
|
+
{
|
|
42
|
+
code: input.targetCurrencyCode,
|
|
43
|
+
},
|
|
44
|
+
ctx,
|
|
45
|
+
);
|
|
43
46
|
|
|
44
47
|
if (!targetCurrency) {
|
|
45
48
|
throw new CurrencyNotFoundError(input.targetCurrencyCode);
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
//
|
|
51
|
+
// Validate both currencies are active
|
|
49
52
|
if (!sourceCurrency.isActive) {
|
|
50
53
|
throw new InactiveCurrencyError(input.sourceCurrencyCode);
|
|
51
54
|
}
|
|
@@ -54,7 +57,7 @@ export const convertAmount = defineQuery(async (db: ReadonlyDB<DB>, input: Conve
|
|
|
54
57
|
throw new InactiveCurrencyError(input.targetCurrencyCode);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
//
|
|
60
|
+
// Same currency - return original amount
|
|
58
61
|
if (sourceCurrency.id === targetCurrency.id) {
|
|
59
62
|
return {
|
|
60
63
|
convertedAmount: input.amount,
|
|
@@ -65,7 +68,7 @@ export const convertAmount = defineQuery(async (db: ReadonlyDB<DB>, input: Conve
|
|
|
65
68
|
};
|
|
66
69
|
}
|
|
67
70
|
|
|
68
|
-
//
|
|
71
|
+
// Find direct exchange rate (most recent on or before conversion date)
|
|
69
72
|
const conversionDate = new Date(input.conversionDate);
|
|
70
73
|
const directRate = await db
|
|
71
74
|
.selectFrom("ExchangeRate")
|
|
@@ -83,7 +86,7 @@ export const convertAmount = defineQuery(async (db: ReadonlyDB<DB>, input: Conve
|
|
|
83
86
|
exchangeRate = directRate.rate;
|
|
84
87
|
exchangeRateRecord = directRate;
|
|
85
88
|
} else {
|
|
86
|
-
//
|
|
89
|
+
// Try inverse rate
|
|
87
90
|
const inverseRate = await db
|
|
88
91
|
.selectFrom("ExchangeRate")
|
|
89
92
|
.selectAll()
|
|
@@ -95,9 +98,7 @@ export const convertAmount = defineQuery(async (db: ReadonlyDB<DB>, input: Conve
|
|
|
95
98
|
|
|
96
99
|
if (!inverseRate) {
|
|
97
100
|
throw new ExchangeRateNotFoundError(
|
|
98
|
-
input.sourceCurrencyCode
|
|
99
|
-
input.targetCurrencyCode,
|
|
100
|
-
input.conversionDate,
|
|
101
|
+
`${input.sourceCurrencyCode} to ${input.targetCurrencyCode} on ${input.conversionDate}`,
|
|
101
102
|
);
|
|
102
103
|
}
|
|
103
104
|
|
|
@@ -105,10 +106,8 @@ export const convertAmount = defineQuery(async (db: ReadonlyDB<DB>, input: Conve
|
|
|
105
106
|
exchangeRateRecord = inverseRate;
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
//
|
|
109
|
+
// Calculate converted amount, rounded to target currency's decimal places
|
|
109
110
|
const rawResult = input.amount * exchangeRate;
|
|
110
|
-
|
|
111
|
-
// 8. Round to target currency's decimal places
|
|
112
111
|
const roundingFactor = Math.pow(10, targetCurrency.decimalPlaces);
|
|
113
112
|
const convertedAmount = Math.round(rawResult * roundingFactor) / roundingFactor;
|
|
114
113
|
|
|
@@ -119,4 +118,4 @@ export const convertAmount = defineQuery(async (db: ReadonlyDB<DB>, input: Conve
|
|
|
119
118
|
targetCurrency,
|
|
120
119
|
exchangeRateRecord,
|
|
121
120
|
};
|
|
122
|
-
}
|
|
121
|
+
}
|
|
@@ -2,7 +2,11 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
import { createMockDb } from "../../testing/index";
|
|
3
3
|
import { DB } from "../generated/kysely-tailordb";
|
|
4
4
|
import type { QueryContext } from "../../shared/internal";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
InactiveUnitError,
|
|
7
|
+
IncompatibleUnitsError,
|
|
8
|
+
UnitNotFoundError,
|
|
9
|
+
} from "../lib/errors.generated";
|
|
6
10
|
import {
|
|
7
11
|
baseUnitGram,
|
|
8
12
|
baseUnitKg,
|
|
@@ -10,7 +14,7 @@ import {
|
|
|
10
14
|
baseUnitPound,
|
|
11
15
|
inactiveUnit,
|
|
12
16
|
} from "../testing/fixtures";
|
|
13
|
-
import { convertQuantity } from "./convertQuantity";
|
|
17
|
+
import { convertQuantity } from "./convertQuantity.generated";
|
|
14
18
|
|
|
15
19
|
describe("convertQuantity", () => {
|
|
16
20
|
const ctx: QueryContext = { actorId: "test-actor" };
|