Skip to main content

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

ConceptDescription
Contractor AssignmentA record that assigns a supplier (contractor) to a service booking with a defined role, line-item detail, and payment terms.
Service BookingThe parent event/job that contractors are assigned to.
SupplierThe external contractor entity (from the suppliers module).
Statusdraftsubmittedreviewed. Transitioning to submitted or reviewed triggers AP bill creation.
Payout StatusTracks whether the contractor has been paid (pending, etc.).
Document NumberAuto-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

MethodPathDescription
POST/contractor-assignmentsCreate a new contractor assignment
GET/contractor-assignmentsList with pagination and search
GET/contractor-assignments/searchSearch with filters (business, status, date range, booking)
GET/contractor-assignments/:idGet by ID
GET/contractor-assignments/:id/pdfGenerate PDF download
GET/contractor-assignments/:id/printGenerate HTML print preview
PATCH/contractor-assignments/:idUpdate
DELETE/contractor-assignments/:idDelete

All endpoints require Bearer authentication.

Search Filters

The /search endpoint supports these query parameters:

  • businessId — UUID, filter by business
  • statusdraft, submitted, or reviewed
  • serviceBookingId — UUID, filter by parent service booking
  • createdAtFrom / createdAtTo — ISO 8601 date range
  • search — free-text search across role, note, supplier name/tax info, booking external ref
  • page, size — pagination
  • orderBy — sortable field (role)
  • orderasc or desc

PDF Options (query params on /pdf)

  • pageSize — default A4
  • marginTop, marginRight, marginBottom, marginLeft — default 20
  • printBackground — default true
  • timeout — default 30000ms
  • templateId — custom template UUID
  • locationId — location-specific template
  • useLocationTemplatetrue/false

Event Integration

When a contractor assignment is created or transitions from draft to submitted/reviewed, an event is emitted:

  • contractorAssignment.createOnCreateContractorAssignmentEvent
  • contractorAssignment.updateOnUpdateContractorAssignmentEvent

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_idbusiness (CASCADE)
  • service_booking_idservice_booking (CASCADE)
  • supplier_idsupplier (RESTRICT)
  • currency_idcurrency (RESTRICT)
  • accounts_payable_bill_idaccounts_payable_bill (SET NULL)

Enum: ContractorAssignmentStatusdraft, submitted, reviewed (defined in packages/global/enums/contractor-assignment.enums.ts)

Design Decisions

  1. JSON columns for detail/paymentDetail — Line items and payment breakdown are stored as JSON to allow flexible schemas without additional join tables.
  2. Event-driven AP integration — Decouples contractor assignments from AP bill creation. The assignment module does not know about AP bills directly.
  3. Transaction-wrapped mutations — Create and update operations use database transactions to ensure atomicity with document number generation.
  4. Hard delete — Assignments are hard-deleted (not soft-deleted). Consider whether a soft-delete approach is needed for audit trails.