StockHistoryController.java
package com.smartsupplypro.inventory.controller;
import com.smartsupplypro.inventory.dto.StockHistoryDTO;
import com.smartsupplypro.inventory.enums.StockChangeReason;
import com.smartsupplypro.inventory.exception.InvalidRequestException;
import com.smartsupplypro.inventory.service.StockHistoryService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
/**
* Stock history audit trail controller providing comprehensive change tracking.
* Supports filtering by item, reason, supplier with pagination and date ranges.
* @see StockHistoryService
* @see controller-patterns.md for audit pattern documentation
*/
@RestController
@RequestMapping("/api/stock-history")
@RequiredArgsConstructor
public class StockHistoryController {
private static final int MAX_PAGE_SIZE = 200;
private final StockHistoryService stockHistoryService;
/**
* Retrieves all stock history entries without pagination.
* @return complete list of stock changes
*/
@PreAuthorize("hasAnyRole('ADMIN','USER')")
@GetMapping
public List<StockHistoryDTO> getAll() {
return stockHistoryService.getAll();
}
/**
* Gets stock history for specific inventory item.
* @param itemId inventory item identifier
* @return list of changes for the item
*/
@PreAuthorize("hasAnyRole('ADMIN','USER')")
@GetMapping("/item/{itemId}")
public List<StockHistoryDTO> getByItemId(@PathVariable String itemId) {
return stockHistoryService.getByItemId(itemId);
}
/**
* Filters stock history by change reason type.
* @param reason stock change reason enum
* @return list of changes matching reason
*/
@PreAuthorize("hasAnyRole('ADMIN','USER')")
@GetMapping("/reason/{reason}")
public List<StockHistoryDTO> getByReason(@PathVariable StockChangeReason reason) {
return stockHistoryService.getByReason(reason);
}
/**
* Advanced paginated search with multiple filter criteria and date bounds.
* @param startDate inclusive start timestamp (ISO-8601)
* @param endDate inclusive end timestamp (ISO-8601)
* @param itemName partial item name filter
* @param supplierId supplier identifier filter
* @param pageable pagination config (max 200 per page, default timestamp DESC)
* @return paginated stock history results
*/
@PreAuthorize("hasAnyRole('ADMIN','USER')")
@GetMapping("/search")
public Page<StockHistoryDTO> search(
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startDate,
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endDate,
@RequestParam(required = false) String itemName,
@RequestParam(required = false) String supplierId,
@PageableDefault(size = 50, sort = "timestamp", direction = Sort.Direction.DESC) Pageable pageable
) {
// Enterprise Comment: Date range validation - prevent logical inconsistencies that could
// cause confusion in audit reports and ensure temporal query validity
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
throw new InvalidRequestException("endDate must be >= startDate");
}
// Enterprise Comment: Page size protection - cap large page requests to prevent memory issues
// and maintain reasonable response times for audit queries over large datasets
pageable = PageRequest.of(
pageable.getPageNumber(),
Math.min(pageable.getPageSize(), MAX_PAGE_SIZE),
pageable.getSort()
);
return stockHistoryService.findFiltered(startDate, endDate, itemName, supplierId, pageable);
}
}