Material Consumptions Module
Records material/product consumption events within a business — typically for production inputs, internal use, or service-related material usage. Each document captures line items with quantities, prices, and taxes, along with payment methods and auto-calculated inventory costs (WAC).
Architecture
apps/backend/src/material-consumptions/
├── material-consumptions.module.ts # NestJS module
├── domain/
│ └── material-consumptions-repository.domain.ts # Repository port
├── application/
│ ├── material-consumptions.service.ts # Use cases
│ └── events/
│ ├── on-create-material-consumption.event.ts
│ ├── on-update-material-consumption.event.ts
│ └── generate-material-consumption-link.dto.ts
├── infrastructure/
│ └── material-consumptions.repository.ts # Kysely adapter
└── interfaces/
├── material-consumptions.controller.ts # HTTP controller
├── dtos/
│ ├── create-material-consumption.dto.ts
│ └── update-material-consumption.dto.ts
└── query/
└── paginate-material-consumptions.query.ts
Layer responsibilities:
| Layer | Responsibility |
|---|---|
| Domain | Repository interface (port). Framework-agnostic. |
| Application | Orchestrates creation, updates, PDF generation, public links. Emits domain events. |
| Infrastructure | Kysely queries against materialConsumption table. Filtering, pagination, transactions. |
| Interfaces | HTTP controllers, DTOs, query objects. Thin — delegates to service. |
Domain Concepts
Material Consumption Document
A document recording consumed materials with:
| Field | Description |
|---|---|
documentNumber | Auto-generated sequential number |
status | draft → submitted → reviewed |
detail | JSON with line items (products, quantities, prices, taxes) |
paymentDetail | JSON with payment method entries |
costDetail | Auto-calculated WAC (weighted average cost) from inventory |
documentDate | Date of the consumption event |
Cost Calculation Flow
On creation, the service:
- Extracts items from
detail - Groups by location and product
- Fetches current inventory quantities and costs
- Calculates WAC per item
- Stores result in
costDetail
Event-Driven Inventory Integration
materialConsumption.create→InventoryOutboundHandlerprocesses stock deductionmaterialConsumption.update→ Re-evaluates if status changed fromdrafttosubmitted/reviewed
API Endpoints
| Method | Path | Description |
|---|---|---|
POST | /material-consumptions | Create a new material consumption |
GET | /material-consumptions | List with pagination, filtering, search |
GET | /material-consumptions/:id | Get by ID |
PATCH | /material-consumptions/:id | Update (partial) |
DELETE | /material-consumptions/:id | Delete |
GET | /material-consumptions/:id/pdf | Download as PDF |
GET | /material-consumptions/:id/pdf/content | Get PDF as base64 JSON |
GET | /material-consumptions/:id/print | HTML print view |
POST | /material-consumptions/:id/public-link | Generate signed public URL |
GET | /material-consumptions/:id/template-data | Get PDF template data |
Query Parameters (List)
| Param | Type | Description |
|---|---|---|
businessId | UUID | Filter by business |
status | string | Filter by status (draft, submitted, reviewed) |
documentNumber | string | Filter by exact document number |
serviceBookingId | UUID | Filter by linked service booking |
createdAtFrom / createdAtTo | ISO date | Created date range |
documentDateFrom / documentDateTo | ISO date | Document date range |
search | string | Search across taxId, taxName, taxAddress, locationName |
size / page | number | Pagination |
orderBy / order | string | Sorting |
PDF Options (Query Params)
| Param | Default | Description |
|---|---|---|
pageSize | A4 | Page size |
marginTop/Right/Bottom/Left | 20 | Margins in pixels |
printBackground | true | Include background |
timeout | 30000 | Render timeout (ms) |
templateId | — | Override template |
locationId | — | Location-specific template |
useLocationTemplate | false | Use location template |
Design Decisions
-
Cost auto-calculation on create — The service calculates WAC from current inventory on document creation. This captures point-in-time costs without requiring the client to compute them.
-
Event-driven inventory — Stock deductions are handled asynchronously via
OnCreateMaterialConsumptionEvent/OnUpdateMaterialConsumptionEvent, keeping the module decoupled from inventory logic. -
Transaction scoping — Document creation (including document number generation, cost calculation, and insert) happens in a single database transaction for consistency.
-
PDF template system — Supports system default, custom, and location-specific templates via the shared
PdfModuleinfrastructure. -
Public link via GCP Cloud Storage — PDF is generated, uploaded to cloud storage, and a time-limited signed URL is returned. Link metadata is stored on the document record.