@invoiceddd/domain
Version:
Domain layer for the InvoiceDDD system - business logic, entities, and domain services
225 lines (172 loc) • 5.15 kB
Markdown
# @invoiceddd/domain
> Core domain logic and business rules for the InvoiceDDD system.
[](https://www.npmjs.com/package/@invoiceddd/domain)
## Overview
This package contains the pure domain logic of the invoice system following Domain-Driven Design principles. It includes entities, value objects, domain services, and business rules with zero dependencies on external frameworks or infrastructure.
## Installation
```bash
npm install @invoiceddd/domain
```
## Key Exports
### Entities
```typescript
import { Invoice, Order, InvoiceAggregate } from '@invoiceddd/domain';
// Create invoice from order data
const invoice = InvoiceAggregate.fromOrder(orderData, {
invoiceNumber: 'INV-1001',
createdBy: 'admin@company.com'
});
```
### Value Objects
```typescript
import {
Money,
CustomerInfo,
InvoiceFinancials,
OrderItem
} from '@invoiceddd/domain';
// Create money value with currency
const price = Money.EUR(29.99);
// Create customer information
const customer = CustomerInfo.create({
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
street: '123 Main St',
city: 'Berlin',
zip: '10115',
country: 'Germany'
});
// Calculate invoice financials
const financials = InvoiceFinancials.calculate({
items: orderItems,
taxRate: 0.19,
shippingCost: Money.EUR(5.99)
});
```
### Domain Services
```typescript
import {
FinancialCalculationService,
InvoiceNumberFormatValidator
} from '@invoiceddd/domain';
// Validate invoice number format
const isValid = InvoiceNumberFormatValidator.validate('INV-1001');
// Calculate totals with business rules
const totals = FinancialCalculationService.calculateTotals(items);
```
### Domain Events
```typescript
import {
InvoiceCreated,
InvoiceDraftRequested,
AllDomainEvents
} from '@invoiceddd/domain';
// Handle domain events
const handleEvent = (event: AllDomainEvents) => {
switch (event._tag) {
case 'InvoiceCreated':
console.log(`Invoice ${event.invoiceNumber} created`);
break;
case 'InvoiceDraftRequested':
console.log(`Draft requested for order ${event.orderId}`);
break;
}
};
```
## Domain Rules
### Invoice Business Rules
- Invoice numbers must be unique and follow configured format
- Invoices are immutable once created
- Customer and item data is snapshotted at creation time
- All financial calculations must be precise (no floating point errors)
### Validation Rules
```typescript
import { validateInvoice, validateOrder } from '@invoiceddd/domain';
// Validate complete invoice data
const result = validateInvoice(invoiceData);
if (result._tag === 'Left') {
console.error('Validation errors:', result.left);
}
// Validate order data
const orderResult = validateOrder(orderData);
```
### Error Handling
```typescript
import {
ValidationError,
BusinessRuleViolationError,
InvoiceValidationError
} from '@invoiceddd/domain';
// Domain-specific error types
try {
const invoice = InvoiceAggregate.create(data);
} catch (error) {
if (error instanceof InvoiceValidationError) {
console.error('Invoice validation failed:', error.details);
}
}
```
## Usage Examples
### Basic Invoice Creation
```typescript
import { InvoiceAggregate, CustomerInfo, OrderItem } from '@invoiceddd/domain';
const customer = CustomerInfo.create({
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
street: '123 Main St',
city: 'Berlin',
zip: '10115',
country: 'Germany'
});
const items = [
OrderItem.create({
name: 'Premium Widget',
unitPrice: 29.99,
quantity: 2
})
];
const invoice = InvoiceAggregate.create({
orderId: 'ORD-001',
invoiceNumber: 'INV-1001',
customer,
items,
createdBy: 'admin@company.com'
});
```
### Financial Calculations
```typescript
import { FinancialCalculationService, Money } from '@invoiceddd/domain';
const items = [
{ unitPrice: Money.EUR(29.99), quantity: 2 },
{ unitPrice: Money.EUR(15.50), quantity: 1 }
];
const calculations = FinancialCalculationService.calculateTotals(items, {
taxRate: 0.19,
shippingCost: Money.EUR(5.99),
discount: Money.EUR(10.00)
});
console.log({
subtotal: calculations.subtotal.amount,
taxes: calculations.taxes.amount,
grandTotal: calculations.grandTotal.amount
});
```
## Dependencies
This package has minimal dependencies:
- `effect` - For functional programming patterns
- `uuid` - For unique identifier generation
## Architecture
The domain layer follows these principles:
- **Pure Functions**: No side effects in domain logic
- **Immutability**: All domain objects are immutable
- **Type Safety**: Full TypeScript coverage with runtime validation
- **Business Rules**: All business logic centralized in domain services
- **Event Sourcing**: Domain events for state changes
## Related Packages
- `@invoiceddd/application` - Use cases and application services
- `@invoiceddd/infrastructure` - External integrations and implementations
- `invoiceddd` - Complete system with easy setup
## Documentation
For complete documentation, see the [main documentation](../../docs/).