TransportOrderController.java

package com.v1rex.liftnexus.transportorder.controller;

import com.v1rex.liftnexus.transportorder.domain.TransportOrderStatus;
import com.v1rex.liftnexus.transportorder.dto.TransportOrderRequest;
import com.v1rex.liftnexus.transportorder.dto.TransportOrderResponse;
import com.v1rex.liftnexus.transportorder.dto.TransportOrderStatusUpdateRequest;
import com.v1rex.liftnexus.transportorder.service.TransportOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import java.net.URI;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

@RestController
@RequestMapping("/api/v1/transport-orders")
@Validated
@RequiredArgsConstructor
@Tag(
    name = "Transport Orders",
    description = "Manage transport orders for moving loads across the warehouse")
public class TransportOrderController {

  private final TransportOrderService transportOrderService;

  @Operation(
      summary = "Get a transport order by ID",
      description =
          "Retrieves details of a specific transport order, including its source/destination bins and assigned forklift.")
  @ApiResponses({
    @ApiResponse(responseCode = "200", description = "Transport order found"),
    @ApiResponse(
        responseCode = "404",
        description = "Transport order not found",
        content = @io.swagger.v3.oas.annotations.media.Content)
  })
  @GetMapping("/{id}")
  public ResponseEntity<TransportOrderResponse> getOrderById(@PathVariable Long id) {
    return ResponseEntity.ok(transportOrderService.findById(id));
  }

  @Operation(
      summary = "Search transport orders",
      description =
          "Search transport orders by status and/or minimum weight. Returns a paginated result set.")
  @ApiResponse(responseCode = "200", description = "Matching transport orders")
  @GetMapping("/search")
  public ResponseEntity<Page<TransportOrderResponse>> searchOrders(
      @Parameter(description = "Filter by order status") @RequestParam(required = false)
          TransportOrderStatus status,
      @Parameter(description = "Minimum weight in kg") @RequestParam(required = false) @Min(1)
          Integer minWeight,
      @PageableDefault(size = 20, sort = "id") Pageable pageable) {
    return ResponseEntity.ok(transportOrderService.searchOrders(status, minWeight, pageable));
  }

  @Operation(
      summary = "Create a new transport order",
      description =
          "Creates a transport order to move a load unit from a source bin to a destination bin.")
  @ApiResponses({
    @ApiResponse(responseCode = "201", description = "Transport order created"),
    @ApiResponse(
        responseCode = "400",
        description = "Invalid input",
        content = @io.swagger.v3.oas.annotations.media.Content)
  })
  @PostMapping
  public ResponseEntity<TransportOrderResponse> createOrder(
      @RequestBody @Valid TransportOrderRequest request) {
    TransportOrderResponse savedOrder = transportOrderService.createTransportOrder(request);

    URI location =
        ServletUriComponentsBuilder.fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(savedOrder.id())
            .toUri();

    return ResponseEntity.created(location).body(savedOrder);
  }

  @Operation(
      summary = "Update transport order status",
      description =
          "Updates the status of a transport order along the lifecycle: OPEN → ASSIGNED → IN_PROGRESS → COMPLETED/FAILED.")
  @ApiResponses({
    @ApiResponse(responseCode = "200", description = "Status updated"),
    @ApiResponse(
        responseCode = "400",
        description = "Invalid state transition",
        content = @io.swagger.v3.oas.annotations.media.Content),
    @ApiResponse(
        responseCode = "404",
        description = "Transport order not found",
        content = @io.swagger.v3.oas.annotations.media.Content)
  })
  @PutMapping("/{id}/status")
  public ResponseEntity<TransportOrderResponse> updateOrderStatus(
      @PathVariable Long id, @RequestBody @Valid TransportOrderStatusUpdateRequest request) {
    return ResponseEntity.ok(transportOrderService.updateOrderStatus(id, request));
  }
}