UNPKG

@invoiceddd/domain

Version:

Domain layer for the InvoiceDDD system - business logic, entities, and domain services

225 lines (172 loc) 5.15 kB
# @invoiceddd/domain > Core domain logic and business rules for the InvoiceDDD system. [![NPM Version](https://img.shields.io/npm/v/@invoiceddd/domain)](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/).