bilhej/backend/src/main/java/se/bilhalsning/controller/AdminController.java
Joakim Mörling ebab892e93 feat: add PATCH /api/admin/orders/{id} for manual tracking entry
- UpdateTrackingRequest DTO: optional trackingId string (nullable —
  allows clearing a tracking ID entered incorrectly)
- OrderService.updateTracking(orderId, trackingId): finds order,
  sets trackingId via setter, saves entity — @PreUpdate fires to
  update the updated_at timestamp automatically
- AdminController.PATCH /api/admin/orders/{id}: admin-only endpoint,
  validates request body with @Valid, returns updated AdminOrderResponse
  via the existing toAdminResponse() mapper
- AdminControllerTest: 5 new tests —
  shouldReturn403WhenPatchingTrackingWithoutAuth,
  shouldReturn403WhenPatchingTrackingAsNonAdmin,
  shouldUpdateTrackingSuccessfully (verifies response id and trackingId),
  shouldClearTrackingWhenNull (removes trackingId),
  shouldReturn404WhenOrderNotFoundForTracking
2026-05-15 19:58:33 +02:00

65 lines
2.3 KiB
Java

package se.bilhalsning.controller;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import se.bilhalsning.dto.AdminOrderResponse;
import se.bilhalsning.dto.UpdateStatusRequest;
import se.bilhalsning.dto.UpdateTrackingRequest;
import se.bilhalsning.entity.Order;
import se.bilhalsning.service.OrderService;
import java.util.List;
import java.util.UUID;
@RestController
@RequestMapping("/api/admin")
@RequiredArgsConstructor
public class AdminController {
private final OrderService orderService;
@GetMapping("/orders")
public ResponseEntity<List<AdminOrderResponse>> listAllOrders() {
List<AdminOrderResponse> orders = orderService.getAllOrders().stream()
.map(this::toAdminResponse)
.toList();
return ResponseEntity.ok(orders);
}
@PatchMapping("/orders/{id}/status")
public ResponseEntity<AdminOrderResponse> updateStatus(
@PathVariable UUID id,
@Valid @RequestBody UpdateStatusRequest request) {
Order order = orderService.updateOrderStatus(id, request.status());
return ResponseEntity.ok(toAdminResponse(order));
}
@PatchMapping("/orders/{id}")
public ResponseEntity<AdminOrderResponse> updateTracking(
@PathVariable UUID id,
@Valid @RequestBody UpdateTrackingRequest request) {
Order order = orderService.updateTracking(id, request.trackingId());
return ResponseEntity.ok(toAdminResponse(order));
}
private AdminOrderResponse toAdminResponse(Order order) {
String email = order.getUser() != null ? order.getUser().getEmail() : "";
return new AdminOrderResponse(
order.getId(),
email,
order.getPlate(),
order.getLetterText(),
order.getStatus().getValue(),
order.getTrackingId(),
order.getAmountPaid(),
order.getCreatedAt()
);
}
}