@tailor-platform/erp-kit 0.0.1 → 0.1.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 +7 -0
- package/LICENSE +21 -0
- package/README.md +196 -28
- package/dist/cli.js +914 -0
- package/package.json +67 -8
- package/schemas/app-compose/actors.yml +34 -0
- package/schemas/app-compose/business-flow.yml +50 -0
- package/schemas/app-compose/requirements.yml +33 -0
- package/schemas/app-compose/resolver.yml +47 -0
- package/schemas/app-compose/screen.yml +81 -0
- package/schemas/app-compose/story.yml +67 -0
- package/schemas/module/command.yml +52 -0
- package/schemas/module/feature.yml +58 -0
- package/schemas/module/model.yml +70 -0
- package/schemas/module/module.yml +50 -0
- package/skills/1-module-docs/SKILL.md +111 -0
- package/skills/1-module-docs/references/structure.md +22 -0
- package/skills/2-module-feature-breakdown/SKILL.md +72 -0
- package/skills/2-module-feature-breakdown/references/commands.md +48 -0
- package/skills/2-module-feature-breakdown/references/models.md +29 -0
- package/skills/2-module-feature-breakdown/references/structure.md +22 -0
- package/skills/3-module-doc-review/SKILL.md +236 -0
- package/skills/3-module-doc-review/references/commands.md +54 -0
- package/skills/3-module-doc-review/references/models.md +29 -0
- package/skills/3-module-doc-review/references/testing.md +37 -0
- package/skills/4-module-tdd-implementation/SKILL.md +74 -0
- package/skills/4-module-tdd-implementation/references/commands.md +45 -0
- package/skills/4-module-tdd-implementation/references/db-relations.md +69 -0
- package/skills/4-module-tdd-implementation/references/errors.md +7 -0
- package/skills/4-module-tdd-implementation/references/exports.md +8 -0
- package/skills/4-module-tdd-implementation/references/models.md +30 -0
- package/skills/4-module-tdd-implementation/references/structure.md +22 -0
- package/skills/4-module-tdd-implementation/references/testing.md +37 -0
- package/skills/5-module-implementation-review/SKILL.md +408 -0
- package/skills/5-module-implementation-review/references/commands.md +45 -0
- package/skills/5-module-implementation-review/references/errors.md +7 -0
- package/skills/5-module-implementation-review/references/exports.md +8 -0
- package/skills/5-module-implementation-review/references/models.md +30 -0
- package/skills/5-module-implementation-review/references/testing.md +29 -0
- package/skills/app-compose-1-requirement-analysis/SKILL.md +89 -0
- package/skills/app-compose-1-requirement-analysis/references/structure.md +27 -0
- package/skills/app-compose-2-requirements-breakdown/SKILL.md +95 -0
- package/skills/app-compose-2-requirements-breakdown/references/screen-detailview.md +106 -0
- package/skills/app-compose-2-requirements-breakdown/references/screen-form.md +139 -0
- package/skills/app-compose-2-requirements-breakdown/references/screen-listview.md +153 -0
- package/skills/app-compose-2-requirements-breakdown/references/structure.md +27 -0
- package/skills/app-compose-3-doc-review/SKILL.md +116 -0
- package/skills/app-compose-3-doc-review/references/structure.md +27 -0
- package/skills/app-compose-4-design-mock/SKILL.md +256 -0
- package/skills/app-compose-4-design-mock/references/component.md +50 -0
- package/skills/app-compose-4-design-mock/references/screen-detailview.md +106 -0
- package/skills/app-compose-4-design-mock/references/screen-form.md +139 -0
- package/skills/app-compose-4-design-mock/references/screen-listview.md +153 -0
- package/skills/app-compose-4-design-mock/references/structure.md +27 -0
- package/skills/app-compose-5-design-mock-review/SKILL.md +290 -0
- package/skills/app-compose-5-design-mock-review/references/component.md +50 -0
- package/skills/app-compose-5-design-mock-review/references/screen-detailview.md +106 -0
- package/skills/app-compose-5-design-mock-review/references/screen-form.md +139 -0
- package/skills/app-compose-5-design-mock-review/references/screen-listview.md +153 -0
- package/skills/app-compose-6-implementation-spec/SKILL.md +127 -0
- package/skills/app-compose-6-implementation-spec/references/auth.md +72 -0
- package/skills/app-compose-6-implementation-spec/references/structure.md +27 -0
- package/skills/mock-scenario/SKILL.md +118 -0
- package/src/app.ts +1 -0
- package/src/cli.ts +120 -0
- package/src/commands/check.test.ts +30 -0
- package/src/commands/check.ts +66 -0
- package/src/commands/init.test.ts +88 -0
- package/src/commands/init.ts +120 -0
- package/src/commands/mock/index.ts +53 -0
- package/src/commands/mock/start.ts +179 -0
- package/src/commands/mock/validate.test.ts +185 -0
- package/src/commands/mock/validate.ts +198 -0
- package/src/commands/scaffold.test.ts +76 -0
- package/src/commands/scaffold.ts +119 -0
- package/src/commands/sync-check.test.ts +125 -0
- package/src/commands/sync-check.ts +182 -0
- package/src/integration.test.ts +63 -0
- package/src/mdschema.ts +48 -0
- package/src/mockServer.ts +55 -0
- package/src/module.ts +86 -0
- package/src/modules/accounting/.gitkeep +0 -0
- package/src/modules/coa-management/.gitkeep +0 -0
- package/src/modules/inventory/.gitkeep +0 -0
- package/src/modules/manufacturing/.gitkeep +0 -0
- package/src/modules/primitives/README.md +39 -0
- package/src/modules/primitives/command/activateCategory.test.ts +75 -0
- package/src/modules/primitives/command/activateCategory.ts +50 -0
- package/src/modules/primitives/command/activateCurrency.test.ts +70 -0
- package/src/modules/primitives/command/activateCurrency.ts +50 -0
- package/src/modules/primitives/command/activateUnit.test.ts +53 -0
- package/src/modules/primitives/command/activateUnit.ts +50 -0
- package/src/modules/primitives/command/convertAmount.test.ts +275 -0
- package/src/modules/primitives/command/convertAmount.ts +126 -0
- package/src/modules/primitives/command/convertQuantity.test.ts +219 -0
- package/src/modules/primitives/command/convertQuantity.ts +73 -0
- package/src/modules/primitives/command/createCategory.test.ts +126 -0
- package/src/modules/primitives/command/createCategory.ts +89 -0
- package/src/modules/primitives/command/createCurrency.test.ts +191 -0
- package/src/modules/primitives/command/createCurrency.ts +77 -0
- package/src/modules/primitives/command/createExchangeRate.test.ts +216 -0
- package/src/modules/primitives/command/createExchangeRate.ts +91 -0
- package/src/modules/primitives/command/createUnit.test.ts +214 -0
- package/src/modules/primitives/command/createUnit.ts +88 -0
- package/src/modules/primitives/command/deactivateCategory.test.ts +97 -0
- package/src/modules/primitives/command/deactivateCategory.ts +62 -0
- package/src/modules/primitives/command/deactivateCurrency.test.ts +85 -0
- package/src/modules/primitives/command/deactivateCurrency.ts +55 -0
- package/src/modules/primitives/command/deactivateUnit.test.ts +78 -0
- package/src/modules/primitives/command/deactivateUnit.ts +62 -0
- package/src/modules/primitives/command/setBaseCurrency.test.ts +98 -0
- package/src/modules/primitives/command/setBaseCurrency.ts +74 -0
- package/src/modules/primitives/command/setReferenceUnit.test.ts +108 -0
- package/src/modules/primitives/command/setReferenceUnit.ts +84 -0
- package/src/modules/primitives/db/currency.ts +30 -0
- package/src/modules/primitives/db/exchangeRate.ts +28 -0
- package/src/modules/primitives/db/unit.ts +32 -0
- package/src/modules/primitives/db/uomCategory.ts +32 -0
- package/src/modules/primitives/docs/commands/ActivateCategory.md +34 -0
- package/src/modules/primitives/docs/commands/ActivateCurrency.md +33 -0
- package/src/modules/primitives/docs/commands/ActivateUnit.md +34 -0
- package/src/modules/primitives/docs/commands/ConvertAmount.md +50 -0
- package/src/modules/primitives/docs/commands/ConvertQuantity.md +43 -0
- package/src/modules/primitives/docs/commands/CreateCategory.md +44 -0
- package/src/modules/primitives/docs/commands/CreateCurrency.md +47 -0
- package/src/modules/primitives/docs/commands/CreateExchangeRate.md +48 -0
- package/src/modules/primitives/docs/commands/CreateUnit.md +48 -0
- package/src/modules/primitives/docs/commands/DeactivateCategory.md +38 -0
- package/src/modules/primitives/docs/commands/DeactivateCurrency.md +38 -0
- package/src/modules/primitives/docs/commands/DeactivateUnit.md +38 -0
- package/src/modules/primitives/docs/commands/SetBaseCurrency.md +39 -0
- package/src/modules/primitives/docs/commands/SetReferenceUnit.md +43 -0
- package/src/modules/primitives/docs/features/currency-definitions.md +55 -0
- package/src/modules/primitives/docs/features/exchange-rates.md +61 -0
- package/src/modules/primitives/docs/features/unit-conversion.md +66 -0
- package/src/modules/primitives/docs/features/uom-categories.md +52 -0
- package/src/modules/primitives/docs/models/Currency.md +45 -0
- package/src/modules/primitives/docs/models/ExchangeRate.md +33 -0
- package/src/modules/primitives/docs/models/Unit.md +46 -0
- package/src/modules/primitives/docs/models/UoMCategory.md +44 -0
- package/src/modules/primitives/generated/kysely-tailordb.ts +95 -0
- package/src/modules/primitives/index.ts +40 -0
- package/src/modules/primitives/lib/errors.ts +138 -0
- package/src/modules/primitives/lib/types.ts +20 -0
- package/src/modules/primitives/module.ts +66 -0
- package/src/modules/primitives/permissions.ts +18 -0
- package/src/modules/primitives/tailor.config.ts +11 -0
- package/src/modules/primitives/testing/fixtures.ts +161 -0
- package/src/modules/product-management/.gitkeep +0 -0
- package/src/modules/purchase/.gitkeep +0 -0
- package/src/modules/sales/.gitkeep +0 -0
- package/src/modules/shared/createContext.test.ts +39 -0
- package/src/modules/shared/createContext.ts +15 -0
- package/src/modules/shared/defineCommand.test.ts +42 -0
- package/src/modules/shared/defineCommand.ts +19 -0
- package/src/modules/shared/definePermissions.test.ts +146 -0
- package/src/modules/shared/definePermissions.ts +94 -0
- package/src/modules/shared/entityTypes.ts +15 -0
- package/src/modules/shared/errors.ts +22 -0
- package/src/modules/shared/index.ts +1 -0
- package/src/modules/shared/internal.ts +13 -0
- package/src/modules/shared/requirePermission.test.ts +47 -0
- package/src/modules/shared/requirePermission.ts +8 -0
- package/src/modules/shared/types.ts +4 -0
- package/src/modules/supplier-management/.gitkeep +0 -0
- package/src/modules/supplier-portal/.gitkeep +0 -0
- package/src/modules/testing/index.ts +120 -0
- package/src/modules/user-management/README.md +38 -0
- package/src/modules/user-management/command/activateUser.test.ts +112 -0
- package/src/modules/user-management/command/activateUser.ts +67 -0
- package/src/modules/user-management/command/assignPermissionToRole.test.ts +119 -0
- package/src/modules/user-management/command/assignPermissionToRole.ts +87 -0
- package/src/modules/user-management/command/assignRoleToUser.test.ts +162 -0
- package/src/modules/user-management/command/assignRoleToUser.ts +93 -0
- package/src/modules/user-management/command/createPermission.test.ts +143 -0
- package/src/modules/user-management/command/createPermission.ts +66 -0
- package/src/modules/user-management/command/createRole.test.ts +115 -0
- package/src/modules/user-management/command/createRole.ts +52 -0
- package/src/modules/user-management/command/createUser.test.ts +198 -0
- package/src/modules/user-management/command/createUser.ts +85 -0
- package/src/modules/user-management/command/deactivateUser.test.ts +112 -0
- package/src/modules/user-management/command/deactivateUser.ts +67 -0
- package/src/modules/user-management/command/logAuditEvent.test.ts +179 -0
- package/src/modules/user-management/command/logAuditEvent.ts +59 -0
- package/src/modules/user-management/command/reactivateUser.test.ts +115 -0
- package/src/modules/user-management/command/reactivateUser.ts +67 -0
- package/src/modules/user-management/command/revokePermissionFromRole.test.ts +112 -0
- package/src/modules/user-management/command/revokePermissionFromRole.ts +81 -0
- package/src/modules/user-management/command/revokeRoleFromUser.test.ts +112 -0
- package/src/modules/user-management/command/revokeRoleFromUser.ts +81 -0
- package/src/modules/user-management/db/auditEvent.ts +47 -0
- package/src/modules/user-management/db/permission.ts +31 -0
- package/src/modules/user-management/db/role.ts +28 -0
- package/src/modules/user-management/db/rolePermission.ts +44 -0
- package/src/modules/user-management/db/user.ts +38 -0
- package/src/modules/user-management/db/userRole.ts +44 -0
- package/src/modules/user-management/docs/commands/ActivateUser.md +36 -0
- package/src/modules/user-management/docs/commands/AssignPermissionToRole.md +39 -0
- package/src/modules/user-management/docs/commands/AssignRoleToUser.md +43 -0
- package/src/modules/user-management/docs/commands/CreatePermission.md +35 -0
- package/src/modules/user-management/docs/commands/CreateRole.md +35 -0
- package/src/modules/user-management/docs/commands/CreateUser.md +41 -0
- package/src/modules/user-management/docs/commands/DeactivateUser.md +38 -0
- package/src/modules/user-management/docs/commands/LogAuditEvent.md +37 -0
- package/src/modules/user-management/docs/commands/ReactivateUser.md +37 -0
- package/src/modules/user-management/docs/commands/RevokePermissionFromRole.md +40 -0
- package/src/modules/user-management/docs/commands/RevokeRoleFromUser.md +40 -0
- package/src/modules/user-management/docs/features/audit-trail.md +80 -0
- package/src/modules/user-management/docs/features/role-based-access-control.md +76 -0
- package/src/modules/user-management/docs/features/user-account-management.md +64 -0
- package/src/modules/user-management/docs/models/AuditEvent.md +34 -0
- package/src/modules/user-management/docs/models/Permission.md +31 -0
- package/src/modules/user-management/docs/models/Role.md +31 -0
- package/src/modules/user-management/docs/models/RolePermission.md +33 -0
- package/src/modules/user-management/docs/models/User.md +47 -0
- package/src/modules/user-management/docs/models/UserRole.md +34 -0
- package/src/modules/user-management/docs/plans/2026-01-30-flattened-permissions-design.md +52 -0
- package/src/modules/user-management/executor/recomputeOnRolePermissionChange.ts +61 -0
- package/src/modules/user-management/generated/enums.ts +24 -0
- package/src/modules/user-management/generated/kysely-tailordb.ts +112 -0
- package/src/modules/user-management/index.ts +32 -0
- package/src/modules/user-management/lib/errors.ts +81 -0
- package/src/modules/user-management/lib/recomputeUserPermissions.ts +53 -0
- package/src/modules/user-management/lib/types.ts +31 -0
- package/src/modules/user-management/module.ts +77 -0
- package/src/modules/user-management/permissions.ts +15 -0
- package/src/modules/user-management/tailor.config.ts +11 -0
- package/src/modules/user-management/testing/fixtures.ts +98 -0
- package/src/schemas.ts +25 -0
- package/src/testing.ts +10 -0
- package/src/util.ts +3 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Exchange Rates
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Exchange Rates maintain the conversion ratios between currency pairs with effective dates. Each rate record specifies the source currency, target currency, rate value, and the date from which it applies. The system uses these rates to convert monetary amounts for transactions, reporting, and consolidation.
|
|
6
|
+
|
|
7
|
+
Rates are date-based to support historical accuracy - a transaction from last month uses last month's rate, not today's rate.
|
|
8
|
+
|
|
9
|
+
## Business Purpose
|
|
10
|
+
|
|
11
|
+
Multi-currency operations require accurate exchange rate management:
|
|
12
|
+
|
|
13
|
+
- **Transaction Recording**: Convert foreign currency invoices to base currency at booking time
|
|
14
|
+
- **Financial Reporting**: Consolidate subsidiaries using period-end rates
|
|
15
|
+
- **Historical Accuracy**: Audit trail requires rates as of transaction date
|
|
16
|
+
- **Variance Analysis**: Compare budgeted rates vs actual rates for currency exposure
|
|
17
|
+
|
|
18
|
+
Exchange rates ensure monetary consistency while maintaining complete audit traceability.
|
|
19
|
+
|
|
20
|
+
## Process Flow
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
flowchart TD
|
|
24
|
+
A[Create Exchange Rate] --> B[Set Currency Pair]
|
|
25
|
+
B --> C[Set Rate Value]
|
|
26
|
+
C --> D[Set Effective Date]
|
|
27
|
+
D --> E{Validate Rate}
|
|
28
|
+
E -->|Invalid| F[Return Error]
|
|
29
|
+
E -->|Valid| G[Save Rate]
|
|
30
|
+
G --> H[Rate Available for Date Range]
|
|
31
|
+
|
|
32
|
+
I[Convert Amount] --> J[Find Rate for Date]
|
|
33
|
+
J --> K{Rate Found?}
|
|
34
|
+
K -->|No| L[Return Error or Use Fallback]
|
|
35
|
+
K -->|Yes| M[Apply Rate × Amount]
|
|
36
|
+
M --> N[Return Converted Amount]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Scenario Patterns
|
|
40
|
+
|
|
41
|
+
- **Daily Rate Updates**: Finance team updates rates daily from central bank or market data feed
|
|
42
|
+
- **Period-End Rates**: Month-end closing uses official rates for consolidation
|
|
43
|
+
- **Historical Lookup**: Generating report for Q1 uses Q1 rates, not current rates
|
|
44
|
+
- **Rate Gap Handling**: Transaction on holiday uses most recent prior rate when exact date unavailable
|
|
45
|
+
- **Inverse Calculation**: Rate for USD→EUR automatically provides EUR→USD by inversion
|
|
46
|
+
|
|
47
|
+
## Test Cases
|
|
48
|
+
|
|
49
|
+
- Creating rate with valid currency pair and positive rate should succeed
|
|
50
|
+
- Rate with zero or negative value should fail validation
|
|
51
|
+
- Rate effective date in far future should be allowed (forward rates)
|
|
52
|
+
- Looking up rate for date should return most recent rate on or before that date
|
|
53
|
+
- Looking up rate with no prior rate should return error or configurable fallback
|
|
54
|
+
- Same currency conversion (USD→USD) should return rate of 1.0
|
|
55
|
+
- Inverse rate calculation should be mathematically correct (1/rate)
|
|
56
|
+
- Updating existing rate for same date should replace previous value
|
|
57
|
+
|
|
58
|
+
## Reference Links
|
|
59
|
+
|
|
60
|
+
- [European Central Bank Exchange Rates](https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html)
|
|
61
|
+
- [Open Exchange Rates API](https://openexchangerates.org/)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Unit Conversion
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Unit Conversion enables automatic quantity transformation between any two units within the same category. The conversion uses the reference unit as an intermediary, ensuring consistent results regardless of which units are involved. This feature supports the core ERP operations where quantities must be expressed in different units for purchasing, inventory, and sales.
|
|
6
|
+
|
|
7
|
+
Conversions include configurable rounding precision to match business requirements for different unit types.
|
|
8
|
+
|
|
9
|
+
## Business Purpose
|
|
10
|
+
|
|
11
|
+
Different stakeholders work with different units:
|
|
12
|
+
|
|
13
|
+
- **Purchasing** buys in bulk units (cases, pallets, drums)
|
|
14
|
+
- **Warehouse** tracks in standardized units (pieces, kilograms, liters)
|
|
15
|
+
- **Sales** sells in customer-friendly units (packs, bottles, individual items)
|
|
16
|
+
- **Manufacturing** measures in precise units (grams, milliliters)
|
|
17
|
+
|
|
18
|
+
Unit conversion eliminates manual calculation errors and ensures inventory accuracy when the same product moves through these different contexts.
|
|
19
|
+
|
|
20
|
+
## Process Flow
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
flowchart TD
|
|
24
|
+
A[Conversion Request] --> B{Same Category?}
|
|
25
|
+
B -->|No| C[Return Error: Incompatible Units]
|
|
26
|
+
B -->|Yes| D[Get Source Unit Factor]
|
|
27
|
+
D --> E[Get Target Unit Factor]
|
|
28
|
+
E --> F[Calculate: Qty × Source Factor ÷ Target Factor]
|
|
29
|
+
F --> G[Apply Rounding Precision]
|
|
30
|
+
G --> H[Return Converted Quantity]
|
|
31
|
+
|
|
32
|
+
subgraph Validation
|
|
33
|
+
B
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
subgraph Calculation
|
|
37
|
+
D
|
|
38
|
+
E
|
|
39
|
+
F
|
|
40
|
+
G
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Scenario Patterns
|
|
45
|
+
|
|
46
|
+
- **Purchase to Inventory**: Vendor ships 10 cases (12 units/case), system records 120 pieces in inventory
|
|
47
|
+
- **Sales Order Fulfillment**: Customer orders 5 kg, warehouse picks 5000 grams from bin tracked in grams
|
|
48
|
+
- **Manufacturing Consumption**: Recipe calls for 500ml, inventory deducts 0.5 liters from stock
|
|
49
|
+
- **Cross-Unit Reporting**: Generate report showing total weight in both kilograms and pounds for different markets
|
|
50
|
+
- **Fractional Handling**: Order for 2.5 dozen converts to 30 pieces for picking
|
|
51
|
+
|
|
52
|
+
## Test Cases
|
|
53
|
+
|
|
54
|
+
- Converting between units in the same category should return correct result
|
|
55
|
+
- Converting between units in different categories should return an error
|
|
56
|
+
- Converting with the same source and target unit should return the original quantity
|
|
57
|
+
- Converting to/from the reference unit should use factor of 1.0
|
|
58
|
+
- Rounding should respect the target unit's precision setting
|
|
59
|
+
- Zero quantity conversion should return zero
|
|
60
|
+
- Negative quantity conversion should be handled consistently (error or allow based on business rules)
|
|
61
|
+
- Very large quantities should not cause overflow errors
|
|
62
|
+
|
|
63
|
+
## Reference Links
|
|
64
|
+
|
|
65
|
+
- [NIST Unit Conversion Guide](https://www.nist.gov/pml/owm/metric-si/unit-conversion)
|
|
66
|
+
- [Odoo UoM Conversion Documentation](https://www.odoo.com/documentation/19.0/applications/inventory_and_mrp/inventory/product_management/configure/uom.html)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# UoM Categories
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
UoM Categories organize units of measure into logical groupings where conversions are meaningful. Each category has a designated reference unit that serves as the base for all conversion calculations within that category. Units can only be converted to other units within the same category.
|
|
6
|
+
|
|
7
|
+
This feature enables businesses to define their measurement standards while maintaining mathematical consistency across all unit conversions.
|
|
8
|
+
|
|
9
|
+
## Business Purpose
|
|
10
|
+
|
|
11
|
+
Organizations need to track quantities in various units depending on context - purchasing in bulk units, selling in retail units, and managing inventory in standardized units. UoM Categories ensure that:
|
|
12
|
+
|
|
13
|
+
- Conversions only occur between compatible units (you cannot convert kilograms to liters)
|
|
14
|
+
- A single source of truth exists for conversion factors via the reference unit
|
|
15
|
+
- New units can be added without updating relationships to every other unit
|
|
16
|
+
- Mathematical precision is maintained through a single conversion path
|
|
17
|
+
|
|
18
|
+
## Process Flow
|
|
19
|
+
|
|
20
|
+
```mermaid
|
|
21
|
+
flowchart TD
|
|
22
|
+
A[Create Category] --> B{Has Reference Unit?}
|
|
23
|
+
B -->|No| C[Create Reference Unit]
|
|
24
|
+
C --> D[Set as Category Reference]
|
|
25
|
+
B -->|Yes| E[Add Additional Units]
|
|
26
|
+
D --> E
|
|
27
|
+
E --> F[Define Conversion Factor]
|
|
28
|
+
F --> G{More Units?}
|
|
29
|
+
G -->|Yes| E
|
|
30
|
+
G -->|No| H[Category Ready]
|
|
31
|
+
H --> I[Products Can Reference Units]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Scenario Patterns
|
|
35
|
+
|
|
36
|
+
- **Initial Setup**: Administrator creates standard categories (Unit, Weight, Volume, Length, Time) with reference units during system initialization
|
|
37
|
+
- **Industry-Specific Units**: Manufacturing adds custom units like "Pallet" or "Roll" to the Unit category with appropriate conversion factors
|
|
38
|
+
- **Regional Adaptation**: Business operating in multiple regions adds both metric and imperial units to Weight and Length categories
|
|
39
|
+
- **Precision Requirements**: Pharmaceutical company creates units with high decimal precision for precise dosage tracking
|
|
40
|
+
|
|
41
|
+
## Test Cases
|
|
42
|
+
|
|
43
|
+
- Creating a category without a reference unit should fail or prompt for reference unit creation
|
|
44
|
+
- Setting a reference unit should automatically set its conversion factor to 1.0
|
|
45
|
+
- Deleting a reference unit should be prevented if other units exist in the category
|
|
46
|
+
- Category names must be unique within the system
|
|
47
|
+
- Deactivating a category should prevent new products from using its units
|
|
48
|
+
|
|
49
|
+
## Reference Links
|
|
50
|
+
|
|
51
|
+
- [Odoo Units of Measure Documentation](https://www.odoo.com/documentation/19.0/applications/inventory_and_mrp/inventory/product_management/configure/uom.html)
|
|
52
|
+
- [ISO 80000 Quantities and Units Standard](https://www.iso.org/standard/76921.html)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Currency
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Currency defines a monetary unit available for use across the ERP system. Each currency contains the ISO 4217 code, display symbol, name, and decimal precision. One currency is designated as the base currency for the organization, serving as the default for reporting and consolidation.
|
|
6
|
+
|
|
7
|
+
Examples: USD (US Dollar), EUR (Euro), JPY (Japanese Yen).
|
|
8
|
+
|
|
9
|
+
## Domain Model Definitions
|
|
10
|
+
|
|
11
|
+
### Model type
|
|
12
|
+
|
|
13
|
+
Stateful
|
|
14
|
+
|
|
15
|
+
#### State Transitions
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
stateDiagram-v2
|
|
19
|
+
[*] --> Active: create
|
|
20
|
+
Active --> Inactive: deactivate
|
|
21
|
+
Inactive --> Active: activate
|
|
22
|
+
note right of Active: Base currency cannot be deactivated
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Command Definitions
|
|
26
|
+
|
|
27
|
+
- [createCurrency](../commands/CreateCurrency.md)
|
|
28
|
+
- [activateCurrency](../commands/ActivateCurrency.md)
|
|
29
|
+
- [deactivateCurrency](../commands/DeactivateCurrency.md)
|
|
30
|
+
- [setBaseCurrency](../commands/SetBaseCurrency.md)
|
|
31
|
+
|
|
32
|
+
### Models
|
|
33
|
+
|
|
34
|
+
- Currency
|
|
35
|
+
|
|
36
|
+
### Invariants
|
|
37
|
+
|
|
38
|
+
- ISO 4217 code must be unique across all currencies
|
|
39
|
+
- Only one currency can be designated as base currency
|
|
40
|
+
- Base currency cannot be deactivated
|
|
41
|
+
|
|
42
|
+
### Relationships
|
|
43
|
+
|
|
44
|
+
- **Referenced By Exchange Rates**: Currency is referenced as source or target in ExchangeRate records
|
|
45
|
+
- **Referenced By Transactions**: Currency is used in sales, purchase, and accounting transactions
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# ExchangeRate
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
ExchangeRate maintains the conversion ratio between a currency pair with an effective date. Each rate record specifies the source currency, target currency, rate value, and the date from which it applies. The system uses these rates to convert monetary amounts for transactions, reporting, and consolidation.
|
|
6
|
+
|
|
7
|
+
Rates are date-based to support historical accuracy - a transaction from last month uses last month's rate, not today's rate.
|
|
8
|
+
|
|
9
|
+
## Domain Model Definitions
|
|
10
|
+
|
|
11
|
+
### Model type
|
|
12
|
+
|
|
13
|
+
AppendOnly
|
|
14
|
+
|
|
15
|
+
### Command Definitions
|
|
16
|
+
|
|
17
|
+
- [createExchangeRate](../commands/CreateExchangeRate.md)
|
|
18
|
+
- [convertAmount](../commands/ConvertAmount.md)
|
|
19
|
+
|
|
20
|
+
### Models
|
|
21
|
+
|
|
22
|
+
- ExchangeRate
|
|
23
|
+
|
|
24
|
+
### Invariants
|
|
25
|
+
|
|
26
|
+
- Rate must be a positive decimal value
|
|
27
|
+
- Source and target currencies must be different
|
|
28
|
+
- Effective date is required for all rate records
|
|
29
|
+
|
|
30
|
+
### Relationships
|
|
31
|
+
|
|
32
|
+
- **Belongs To Source Currency**: Each rate has exactly one source currency
|
|
33
|
+
- **Belongs To Target Currency**: Each rate has exactly one target currency
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Unit
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Unit defines an individual unit of measure with its symbol, display name, and conversion factor relative to its category's reference unit. Units support configurable rounding precision for business operations.
|
|
6
|
+
|
|
7
|
+
Examples: kg (kilogram), lb (pound), ea (each), dz (dozen).
|
|
8
|
+
|
|
9
|
+
## Domain Model Definitions
|
|
10
|
+
|
|
11
|
+
### Model type
|
|
12
|
+
|
|
13
|
+
Stateful
|
|
14
|
+
|
|
15
|
+
#### State Transitions
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
stateDiagram-v2
|
|
19
|
+
[*] --> Active: create
|
|
20
|
+
Active --> Inactive: deactivate
|
|
21
|
+
Inactive --> Active: activate
|
|
22
|
+
note right of Active: Reference unit cannot be deactivated
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Command Definitions
|
|
26
|
+
|
|
27
|
+
- [createUnit](../commands/CreateUnit.md)
|
|
28
|
+
- [activateUnit](../commands/ActivateUnit.md)
|
|
29
|
+
- [deactivateUnit](../commands/DeactivateUnit.md)
|
|
30
|
+
- [convertQuantity](../commands/ConvertQuantity.md)
|
|
31
|
+
|
|
32
|
+
### Models
|
|
33
|
+
|
|
34
|
+
- Unit
|
|
35
|
+
|
|
36
|
+
### Invariants
|
|
37
|
+
|
|
38
|
+
- Conversion factor must be a positive value
|
|
39
|
+
- Reference unit has conversion factor of 1.0
|
|
40
|
+
- Symbol must be unique within the category
|
|
41
|
+
- Reference unit cannot be deactivated
|
|
42
|
+
|
|
43
|
+
### Relationships
|
|
44
|
+
|
|
45
|
+
- **Belongs To Category**: Each unit belongs to exactly one UoMCategory
|
|
46
|
+
- **May Be Reference Unit**: A unit may be designated as its category's reference unit
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# UoMCategory
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
UoMCategory organizes units of measure into logical groupings where conversions are meaningful. Each category has a designated reference unit that serves as the base for all conversion calculations within that category. Units can only be converted to other units within the same category.
|
|
6
|
+
|
|
7
|
+
Examples: Unit, Weight, Volume, Length, Time.
|
|
8
|
+
|
|
9
|
+
## Domain Model Definitions
|
|
10
|
+
|
|
11
|
+
### Model type
|
|
12
|
+
|
|
13
|
+
Stateful
|
|
14
|
+
|
|
15
|
+
#### State Transitions
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
stateDiagram-v2
|
|
19
|
+
[*] --> Active: create
|
|
20
|
+
Active --> Inactive: deactivate
|
|
21
|
+
Inactive --> Active: activate
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Command Definitions
|
|
25
|
+
|
|
26
|
+
- [createCategory](../commands/CreateCategory.md)
|
|
27
|
+
- [activateCategory](../commands/ActivateCategory.md)
|
|
28
|
+
- [deactivateCategory](../commands/DeactivateCategory.md)
|
|
29
|
+
- [setReferenceUnit](../commands/SetReferenceUnit.md)
|
|
30
|
+
|
|
31
|
+
### Models
|
|
32
|
+
|
|
33
|
+
- UoMCategory
|
|
34
|
+
|
|
35
|
+
### Invariants
|
|
36
|
+
|
|
37
|
+
- Category name must be unique
|
|
38
|
+
- Reference unit must belong to this category
|
|
39
|
+
- Category cannot be deactivated while it has active units
|
|
40
|
+
|
|
41
|
+
### Relationships
|
|
42
|
+
|
|
43
|
+
- **Has Many Units**: A category contains multiple units (one-to-many)
|
|
44
|
+
- **Has One Reference Unit**: Each category designates one unit as the reference unit for conversions
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ColumnType,
|
|
3
|
+
Kysely,
|
|
4
|
+
type KyselyConfig,
|
|
5
|
+
type Transaction as KyselyTransaction,
|
|
6
|
+
type Insertable as KyselyInsertable,
|
|
7
|
+
type Selectable as KyselySelectable,
|
|
8
|
+
type Updateable as KyselyUpdateable,
|
|
9
|
+
} from "kysely";
|
|
10
|
+
import { TailordbDialect } from "@tailor-platform/function-kysely-tailordb";
|
|
11
|
+
|
|
12
|
+
type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
|
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>;
|
|
17
|
+
|
|
18
|
+
export interface Namespace {
|
|
19
|
+
"main-db": {
|
|
20
|
+
Currency: {
|
|
21
|
+
id: Generated<string>;
|
|
22
|
+
code: string;
|
|
23
|
+
name: string;
|
|
24
|
+
symbol: string;
|
|
25
|
+
decimalPlaces: number;
|
|
26
|
+
isBaseCurrency: boolean;
|
|
27
|
+
isActive: boolean;
|
|
28
|
+
createdAt: Generated<Timestamp>;
|
|
29
|
+
updatedAt: Timestamp | null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
ExchangeRate: {
|
|
33
|
+
id: Generated<string>;
|
|
34
|
+
sourceCurrencyId: string;
|
|
35
|
+
targetCurrencyId: string;
|
|
36
|
+
rate: number;
|
|
37
|
+
effectiveDate: Timestamp;
|
|
38
|
+
createdAt: Generated<Timestamp>;
|
|
39
|
+
updatedAt: Timestamp | null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
Unit: {
|
|
43
|
+
id: Generated<string>;
|
|
44
|
+
name: string;
|
|
45
|
+
symbol: string;
|
|
46
|
+
categoryId: string;
|
|
47
|
+
conversionFactor: number;
|
|
48
|
+
roundingPrecision: number;
|
|
49
|
+
isActive: boolean;
|
|
50
|
+
createdAt: Generated<Timestamp>;
|
|
51
|
+
updatedAt: Timestamp | null;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
UoMCategory: {
|
|
55
|
+
id: Generated<string>;
|
|
56
|
+
name: string;
|
|
57
|
+
description: string | null;
|
|
58
|
+
referenceUnitId: string | null;
|
|
59
|
+
isActive: boolean;
|
|
60
|
+
createdAt: Generated<Timestamp>;
|
|
61
|
+
updatedAt: Timestamp | null;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getDB<const N extends keyof Namespace>(
|
|
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
|
+
}
|
|
76
|
+
|
|
77
|
+
export type DB<N extends keyof Namespace = keyof Namespace> = ReturnType<typeof getDB<N>>;
|
|
78
|
+
|
|
79
|
+
export type Transaction<K extends keyof Namespace | DB = keyof Namespace> =
|
|
80
|
+
K extends DB<infer N>
|
|
81
|
+
? KyselyTransaction<Namespace[N]>
|
|
82
|
+
: K extends keyof Namespace
|
|
83
|
+
? KyselyTransaction<Namespace[K]>
|
|
84
|
+
: never;
|
|
85
|
+
|
|
86
|
+
type TableName = {
|
|
87
|
+
[N in keyof Namespace]: keyof Namespace[N];
|
|
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];
|
|
92
|
+
|
|
93
|
+
export type Insertable<T extends keyof Namespace[keyof Namespace]> = KyselyInsertable<Table<T>>;
|
|
94
|
+
export type Selectable<T extends keyof Namespace[keyof Namespace]> = KyselySelectable<Table<T>>;
|
|
95
|
+
export type Updateable<T extends keyof Namespace[keyof Namespace]> = KyselyUpdateable<Table<T>>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export { defineModule } from "./module";
|
|
2
|
+
export { permissions, own, all } from "./permissions";
|
|
3
|
+
|
|
4
|
+
// errors
|
|
5
|
+
export {
|
|
6
|
+
UoMCategoryNotFoundError,
|
|
7
|
+
UnitNotFoundError,
|
|
8
|
+
IncompatibleUnitsError,
|
|
9
|
+
InactiveUnitError,
|
|
10
|
+
CurrencyNotFoundError,
|
|
11
|
+
InactiveCurrencyError,
|
|
12
|
+
ExchangeRateNotFoundError,
|
|
13
|
+
CannotDeactivateReferenceUnitError,
|
|
14
|
+
CategoryNotActiveError,
|
|
15
|
+
DuplicateUnitSymbolError,
|
|
16
|
+
InvalidConversionFactorError,
|
|
17
|
+
InvalidRoundingPrecisionError,
|
|
18
|
+
DuplicateCategoryNameError,
|
|
19
|
+
CategoryHasActiveUnitsError,
|
|
20
|
+
UnitNotInCategoryError,
|
|
21
|
+
InvalidISOCodeError,
|
|
22
|
+
DuplicateCurrencyCodeError,
|
|
23
|
+
InvalidDecimalPlacesError,
|
|
24
|
+
CannotDeactivateBaseCurrencyError,
|
|
25
|
+
CannotSetInactiveAsBaseCurrencyError,
|
|
26
|
+
SameCurrencyPairError,
|
|
27
|
+
InvalidExchangeRateError,
|
|
28
|
+
} from "./lib/errors";
|
|
29
|
+
|
|
30
|
+
// input types
|
|
31
|
+
export { type ConvertQuantityInput } from "./command/convertQuantity";
|
|
32
|
+
export { type ActivateCategoryInput } from "./command/activateCategory";
|
|
33
|
+
export { type DeactivateCategoryInput } from "./command/deactivateCategory";
|
|
34
|
+
export { type SetReferenceUnitInput } from "./command/setReferenceUnit";
|
|
35
|
+
export { type ActivateUnitInput } from "./command/activateUnit";
|
|
36
|
+
export { type DeactivateUnitInput } from "./command/deactivateUnit";
|
|
37
|
+
export { type ConvertAmountInput } from "./command/convertAmount";
|
|
38
|
+
export { type ActivateCurrencyInput } from "./command/activateCurrency";
|
|
39
|
+
export { type DeactivateCurrencyInput } from "./command/deactivateCurrency";
|
|
40
|
+
export { type SetBaseCurrencyInput } from "./command/setBaseCurrency";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { createDomainError } from "../../shared/internal";
|
|
2
|
+
|
|
3
|
+
export const UoMCategoryNotFoundError = createDomainError(
|
|
4
|
+
"UoMCategoryNotFoundError",
|
|
5
|
+
"UOM_CATEGORY_NOT_FOUND",
|
|
6
|
+
(identifier: string) => `UoM category not found: ${identifier}`,
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export const UnitNotFoundError = createDomainError(
|
|
10
|
+
"UnitNotFoundError",
|
|
11
|
+
"UNIT_NOT_FOUND",
|
|
12
|
+
(symbol: string) => `Unit not found: ${symbol}`,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export const IncompatibleUnitsError = createDomainError(
|
|
16
|
+
"IncompatibleUnitsError",
|
|
17
|
+
"INCOMPATIBLE_UNITS",
|
|
18
|
+
(sourceSymbol: string, targetSymbol: string) =>
|
|
19
|
+
`Cannot convert between incompatible units: ${sourceSymbol} and ${targetSymbol} belong to different categories`,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export const InactiveUnitError = createDomainError(
|
|
23
|
+
"InactiveUnitError",
|
|
24
|
+
"INACTIVE_UNIT",
|
|
25
|
+
(symbol: string) => `Unit is inactive: ${symbol}`,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export const CurrencyNotFoundError = createDomainError(
|
|
29
|
+
"CurrencyNotFoundError",
|
|
30
|
+
"CURRENCY_NOT_FOUND",
|
|
31
|
+
(code: string) => `Currency not found: ${code}`,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const InactiveCurrencyError = createDomainError(
|
|
35
|
+
"InactiveCurrencyError",
|
|
36
|
+
"INACTIVE_CURRENCY",
|
|
37
|
+
(code: string) => `Currency is inactive: ${code}`,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export const ExchangeRateNotFoundError = createDomainError(
|
|
41
|
+
"ExchangeRateNotFoundError",
|
|
42
|
+
"EXCHANGE_RATE_NOT_FOUND",
|
|
43
|
+
(sourceCode: string, targetCode: string, date: string) =>
|
|
44
|
+
`No exchange rate found for ${sourceCode} to ${targetCode} on or before ${date}`,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const CannotDeactivateReferenceUnitError = createDomainError(
|
|
48
|
+
"CannotDeactivateReferenceUnitError",
|
|
49
|
+
"CANNOT_DEACTIVATE_REFERENCE_UNIT",
|
|
50
|
+
(unitId: string) => `Cannot deactivate reference unit: ${unitId}. Change reference unit first.`,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
export const CategoryNotActiveError = createDomainError(
|
|
54
|
+
"CategoryNotActiveError",
|
|
55
|
+
"CATEGORY_NOT_ACTIVE",
|
|
56
|
+
(categoryId: string) => `Category is not active: ${categoryId}`,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export const DuplicateUnitSymbolError = createDomainError(
|
|
60
|
+
"DuplicateUnitSymbolError",
|
|
61
|
+
"DUPLICATE_UNIT_SYMBOL",
|
|
62
|
+
(symbol: string, categoryId: string) =>
|
|
63
|
+
`Unit with symbol "${symbol}" already exists in category ${categoryId}`,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
export const InvalidConversionFactorError = createDomainError(
|
|
67
|
+
"InvalidConversionFactorError",
|
|
68
|
+
"INVALID_CONVERSION_FACTOR",
|
|
69
|
+
(factor: number) => `Conversion factor must be positive: ${factor}`,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
export const InvalidRoundingPrecisionError = createDomainError(
|
|
73
|
+
"InvalidRoundingPrecisionError",
|
|
74
|
+
"INVALID_ROUNDING_PRECISION",
|
|
75
|
+
(precision: number) => `Rounding precision must be non-negative: ${precision}`,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
export const DuplicateCategoryNameError = createDomainError(
|
|
79
|
+
"DuplicateCategoryNameError",
|
|
80
|
+
"DUPLICATE_CATEGORY_NAME",
|
|
81
|
+
(name: string) => `Category with name "${name}" already exists`,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
export const CategoryHasActiveUnitsError = createDomainError(
|
|
85
|
+
"CategoryHasActiveUnitsError",
|
|
86
|
+
"CATEGORY_HAS_ACTIVE_UNITS",
|
|
87
|
+
(categoryId: string) => `Cannot deactivate category ${categoryId}: has active units`,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
export const UnitNotInCategoryError = createDomainError(
|
|
91
|
+
"UnitNotInCategoryError",
|
|
92
|
+
"UNIT_NOT_IN_CATEGORY",
|
|
93
|
+
(unitId: string, categoryId: string) =>
|
|
94
|
+
`Unit ${unitId} does not belong to category ${categoryId}`,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
export const InvalidISOCodeError = createDomainError(
|
|
98
|
+
"InvalidISOCodeError",
|
|
99
|
+
"INVALID_ISO_CODE",
|
|
100
|
+
(code: string) => `Invalid ISO 4217 code: "${code}". Must be exactly 3 uppercase letters.`,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
export const DuplicateCurrencyCodeError = createDomainError(
|
|
104
|
+
"DuplicateCurrencyCodeError",
|
|
105
|
+
"DUPLICATE_CURRENCY_CODE",
|
|
106
|
+
(code: string) => `Currency with code "${code}" already exists`,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
export const InvalidDecimalPlacesError = createDomainError(
|
|
110
|
+
"InvalidDecimalPlacesError",
|
|
111
|
+
"INVALID_DECIMAL_PLACES",
|
|
112
|
+
(decimalPlaces: number) => `Decimal places must be between 0 and 4: ${decimalPlaces}`,
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
export const CannotDeactivateBaseCurrencyError = createDomainError(
|
|
116
|
+
"CannotDeactivateBaseCurrencyError",
|
|
117
|
+
"CANNOT_DEACTIVATE_BASE_CURRENCY",
|
|
118
|
+
(currencyId: string) =>
|
|
119
|
+
`Cannot deactivate base currency: ${currencyId}. Change base currency first.`,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
export const CannotSetInactiveAsBaseCurrencyError = createDomainError(
|
|
123
|
+
"CannotSetInactiveAsBaseCurrencyError",
|
|
124
|
+
"CANNOT_SET_INACTIVE_AS_BASE_CURRENCY",
|
|
125
|
+
(currencyId: string) => `Cannot set inactive currency as base: ${currencyId}. Activate it first.`,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
export const SameCurrencyPairError = createDomainError(
|
|
129
|
+
"SameCurrencyPairError",
|
|
130
|
+
"SAME_CURRENCY_PAIR",
|
|
131
|
+
(currencyId: string) => `Source and target currency cannot be the same: ${currencyId}`,
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
export const InvalidExchangeRateError = createDomainError(
|
|
135
|
+
"InvalidExchangeRateError",
|
|
136
|
+
"INVALID_EXCHANGE_RATE",
|
|
137
|
+
(rate: number) => `Exchange rate must be positive: ${rate}`,
|
|
138
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { InferSchema, Selectable, Insertable, Updateable } from "../../shared/internal";
|
|
2
|
+
import type { DB } from "../generated/kysely-tailordb";
|
|
3
|
+
|
|
4
|
+
export type Schema = InferSchema<DB>;
|
|
5
|
+
|
|
6
|
+
export type UoMCategory<T extends { UoMCategory: object }> = Selectable<T["UoMCategory"]>;
|
|
7
|
+
export type UoMCategoryCreate<T extends { UoMCategory: object }> = Insertable<T["UoMCategory"]>;
|
|
8
|
+
export type UoMCategoryUpdate<T extends { UoMCategory: object }> = Updateable<T["UoMCategory"]>;
|
|
9
|
+
|
|
10
|
+
export type Unit<T extends { Unit: object }> = Selectable<T["Unit"]>;
|
|
11
|
+
export type UnitCreate<T extends { Unit: object }> = Insertable<T["Unit"]>;
|
|
12
|
+
export type UnitUpdate<T extends { Unit: object }> = Updateable<T["Unit"]>;
|
|
13
|
+
|
|
14
|
+
export type Currency<T extends { Currency: object }> = Selectable<T["Currency"]>;
|
|
15
|
+
export type CurrencyCreate<T extends { Currency: object }> = Insertable<T["Currency"]>;
|
|
16
|
+
export type CurrencyUpdate<T extends { Currency: object }> = Updateable<T["Currency"]>;
|
|
17
|
+
|
|
18
|
+
export type ExchangeRate<T extends { ExchangeRate: object }> = Selectable<T["ExchangeRate"]>;
|
|
19
|
+
export type ExchangeRateCreate<T extends { ExchangeRate: object }> = Insertable<T["ExchangeRate"]>;
|
|
20
|
+
export type ExchangeRateUpdate<T extends { ExchangeRate: object }> = Updateable<T["ExchangeRate"]>;
|