Saltar al contenido principal

Transfer Requests

Overview

The Transfer Requests module manages the request/approval workflow that precedes inter-location inventory transfers. A transfer request captures the intent to move inventory between locations and goes through an approval flow before an actual inventory transfer is created.

Each transfer request tracks:

  • Origin and destination locations
  • Items requested for transfer (products, quantities)
  • Cost detail calculated from current inventory WAC (Weighted Average Cost)
  • Approval workflow (approver, approval date)
  • Linked inventory transfer (populated after the transfer is created)
  • Document number auto-generated for reference

Architecture

transfers-request/
├── transfers-request.module.ts # NestJS module
├── domain/
│ └── transfers-request-repository.domain.ts # Port interface + sortable keys
├── application/
│ ├── transfers-request.service.ts # Use cases + event handlers
│ └── events/
│ ├── on-create-transfer-request.event.ts # Emitted on create
│ └── on-update-transfer-request.event.ts # Emitted on update
├── infrastructure/
│ └── transfers-request.repository.ts # Kysely adapter
└── interfaces/
├── transfers-request.controller.ts # HTTP routes
├── dtos/
│ ├── create-transfer-request.dto.ts
│ └── update-transfer-request.dto.ts
└── query/
└── paginate-transfers-request.query.ts

Layer Responsibilities

LayerResponsibility
DomainRepository interface (port), sortable key definitions — no framework dependencies
ApplicationBusiness logic: cost calculation, document number generation, event handling for inventory transfer linkage
InfrastructureKysely database queries implementing the domain port
InterfacesHTTP controllers, DTOs, query objects, Swagger documentation

Domain Concepts

Transfer Request Lifecycle

  1. Draft — Created with item details; costs auto-calculated from inventory WAC
  2. Pending — Submitted for approval
  3. Approved — Approved by a manager; can trigger creation of an inventory transfer
  4. Rejected — Denied; no further action

Cost Detail

On create/update, the service:

  1. Extracts items from the detail JSON
  2. Groups items by location and product
  3. Fetches current WAC costs from inventory
  4. Calculates cost detail using shared utility functions

Cost detail is recalculated on update only when the items detail has changed (compared via stable JSON stringify).

Inventory Transfer Linkage

When an inventory transfer is created from an approved transfer request, the OnCreateInventoryTransferEvent is consumed to link the two records:

  • inventoryTransferId — UUID of the created transfer
  • inventoryTransferData — metadata snapshot (e.g., document number)

API Endpoints

MethodPathDescription
POST/transfers-requestCreate a new transfer request
GET/transfers-requestList transfer requests (paginated)
GET/transfers-request/searchSearch with filters (date ranges, status, locations)
GET/transfers-request/:idGet transfer request by ID
GET/transfers-request/:id/pdfDownload PDF document
GET/transfers-request/:id/printGet HTML print view
PATCH/transfers-request/:idUpdate transfer request
DELETE/transfers-request/:idDelete transfer request

Search Filters

The GET /search endpoint supports:

  • businessId — filter by business UUID
  • status — filter by status (draft, pending, approved, rejected)
  • originLocationId / destinationLocationId — filter by location
  • createdAtFrom / createdAtTo — date range on creation date
  • transferDateFrom / transferDateTo — date range on requested transfer date
  • search — free-text search on document number and location names
  • Standard pagination: page, size, orderBy, order

Event Integration

Events Emitted

EventWhen
transferRequest.createAfter a transfer request is created
transferRequest.updateAfter a transfer request is updated

Events Consumed

EventAction
inventoryTransfer.createLinks the created inventory transfer to the originating transfer request

Design Decisions

  1. Repository injected via domain token — The service depends on ITransfersRequestRepository (domain port) via TRANSFERS_REQUEST_REPOSITORY Symbol, enabling testability and respecting hexagonal boundaries.

  2. Cost calculated at request time — WAC is captured when the request is created/updated, giving approvers visibility into the financial impact before approving.

  3. Shared date-range utility — Repository uses buildDateRangeCondition from @/utils/date-range-filter.utils for consistent date filtering across all inventory modules.

  4. Sortable keys defined in domain — The sortableTransferRequestKeys constant lives in the domain layer since it represents a domain concept (which fields support sorting), avoiding a dependency inversion from domain to interfaces.