Contractor Assignments
Manages contractor assignments to service bookings — linking external suppliers/contractors to specific services with full financial detail, payment breakdown, and PDF document generation.
Domain Concepts
| Concept | Description |
|---|---|
| Contractor Assignment | A record that assigns a supplier (contractor) to a service booking with a defined role, line-item detail, and payment terms. |
| Service Booking | The parent event/job that contractors are assigned to. |
| Supplier | The external contractor entity (from the suppliers module). |
| Status | draft → submitted → reviewed. Transitioning to submitted or reviewed triggers AP bill creation. |
| Payout Status | Tracks whether the contractor has been paid (pending, etc.). |
| Document Number | Auto-generated sequential number per business. |
Architecture
contractor-assignments/
├── domain/
│ └── contractor-assignments-repository.domain.ts # Port interface + sortable keys
├── application/
│ ├── contractor-assignments.service.ts # Use cases
│ └── events/
│ ├── on-create-contractor-assignment.event.ts
│ └── on-update-contractor-assignment.event.ts
├── infrastructure/
│ └── contractor-assignments.repository.ts # Kysely adapter
└── interfaces/
├── contractor-assignments.controller.ts # HTTP endpoints
├── dtos/
│ ├── create-contractor-assignment.dto.ts
│ └── update-contractor-assignment.dto.ts
└── query/
└── paginate-contractor-assignments.query.ts
Dependency injection uses a Symbol token (CONTRACTOR_ASSIGNMENTS_REPOSITORY)
so the service depends only on the domain interface, not the concrete Kysely
implementation.
API Endpoints
| Method | Path | Description |
|---|---|---|
POST | /contractor-assignments | Create a new contractor assignment |
GET | /contractor-assignments | List with pagination and search |
GET | /contractor-assignments/search | Search with filters (business, status, date range, booking) |
GET | /contractor-assignments/:id | Get by ID |
GET | /contractor-assignments/:id/pdf | Generate PDF download |
GET | /contractor-assignments/:id/print | Generate HTML print preview |
PATCH | /contractor-assignments/:id | Update |
DELETE | /contractor-assignments/:id | Delete |
All endpoints require Bearer authentication.
Search Filters
The /search endpoint supports these query parameters:
businessId— UUID, filter by businessstatus—draft,submitted, orreviewedserviceBookingId— UUID, filter by parent service bookingcreatedAtFrom/createdAtTo— ISO 8601 date rangesearch— free-text search across role, note, supplier name/tax info, booking external refpage,size— paginationorderBy— sortable field (role)order—ascordesc
PDF Options (query params on /pdf)
pageSize— defaultA4marginTop,marginRight,marginBottom,marginLeft— default20printBackground— defaulttruetimeout— default30000mstemplateId— custom template UUIDlocationId— location-specific templateuseLocationTemplate—true/false
Event Integration
When a contractor assignment is created or transitions from draft to
submitted/reviewed, an event is emitted:
contractorAssignment.create→OnCreateContractorAssignmentEventcontractorAssignment.update→OnUpdateContractorAssignmentEvent
The accounts-payable-bills module listens to these events and automatically creates AP bill records for payment methods that generate accounts payable.
Database
Table: contractor_assignment
Key foreign keys:
business_id→business(CASCADE)service_booking_id→service_booking(CASCADE)supplier_id→supplier(RESTRICT)currency_id→currency(RESTRICT)accounts_payable_bill_id→accounts_payable_bill(SET NULL)
Enum: ContractorAssignmentStatus — draft, submitted, reviewed
(defined in packages/global/enums/contractor-assignment.enums.ts)
Design Decisions
- JSON columns for detail/paymentDetail — Line items and payment breakdown are stored as JSON to allow flexible schemas without additional join tables.
- Event-driven AP integration — Decouples contractor assignments from AP bill creation. The assignment module does not know about AP bills directly.
- Transaction-wrapped mutations — Create and update operations use database transactions to ensure atomicity with document number generation.
- Hard delete — Assignments are hard-deleted (not soft-deleted). Consider whether a soft-delete approach is needed for audit trails.