added a /product/id end point for product summary pages

This commit is contained in:
2025-12-09 06:11:18 -05:00
parent b428918489
commit 2049f62f99
5 changed files with 90 additions and 0 deletions

View File

@@ -3,12 +3,14 @@ package group.goforward.battlbuilder.controllers;
import group.goforward.battlbuilder.model.Product;
import group.goforward.battlbuilder.model.ProductOffer;
import group.goforward.battlbuilder.repos.ProductOfferRepository;
import group.goforward.battlbuilder.web.dto.ProductDto;
import group.goforward.battlbuilder.web.dto.ProductOfferDto;
import group.goforward.battlbuilder.repos.ProductRepository;
import group.goforward.battlbuilder.web.dto.ProductSummaryDto;
import group.goforward.battlbuilder.web.mapper.ProductMapper;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import java.math.BigDecimal;
import java.util.*;
@@ -134,4 +136,20 @@ public class ProductController {
.min(Comparator.comparing(ProductOffer::getEffectivePrice))
.orElse(null);
}
@GetMapping("/gunbuilder/products/{id}")
public ResponseEntity<ProductSummaryDto> getGunbuilderProductById(@PathVariable("id") Integer productId) {
return productRepository.findById(productId)
.map(product -> {
List<ProductOffer> offers = productOfferRepository.findByProductId(productId);
ProductOffer bestOffer = pickBestOffer(offers);
BigDecimal price = bestOffer != null ? bestOffer.getEffectivePrice() : null;
String buyUrl = bestOffer != null ? bestOffer.getBuyUrl() : null;
return ProductMapper.toSummary(product, price, buyUrl);
})
.map(ResponseEntity::ok)
.orElseGet(() -> ResponseEntity.notFound().build());
}
}

View File

@@ -12,6 +12,7 @@ import group.goforward.battlbuilder.model.ImportStatus;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.Optional;
@Service
@@ -132,6 +133,44 @@ public class GunbuilderProductService {
return listGunbuilderProducts(platform, partRoles);
}
public Optional<GunbuilderProductDto> getGunbuilderProductById(String id) {
if (id == null || id.isBlank()) {
return Optional.empty();
}
Integer numericId;
try {
numericId = Integer.parseInt(id);
} catch (NumberFormatException ex) {
return Optional.empty();
}
return productRepository.findById(numericId)
.map(p -> {
String platform = p.getPlatform();
PartCategory cat = partCategoryResolverService
.resolveForPlatformAndPartRole(platform, p.getPartRole())
.orElse(null);
String categorySlug = (cat != null) ? cat.getSlug() : "unmapped";
String categoryGroup = (cat != null) ? cat.getGroupName() : "Unmapped";
return new GunbuilderProductDto(
p.getId(),
p.getName(),
p.getBrand().getName(),
platform,
p.getPartRole(),
p.getBestOfferPrice(),
p.getMainImageUrl(),
p.getBestOfferBuyUrl(),
categorySlug,
categoryGroup
);
});
}
/**
* Tiny helper used ONLY by /test-products-db to prove DB wiring.
*/

View File

@@ -0,0 +1,23 @@
// src/main/java/com/ballistic/gunbuilder/api/dto/GunbuilderProductDto.java
package group.goforward.battlbuilder.web.dto;
import java.math.BigDecimal;
public class ProductDto {
private String id;
private String name;
private String brand;
private String platform;
private String partRole;
private BigDecimal price;
private String imageUrl;
private String buyUrl;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

View File

@@ -12,6 +12,8 @@ public class ProductSummaryDto {
private String categoryKey;
private BigDecimal price;
private String buyUrl;
private String imageUrl;
public String getId() {
return id;
@@ -76,4 +78,8 @@ public class ProductSummaryDto {
public void setBuyUrl(String buyUrl) {
this.buyUrl = buyUrl;
}
public String getImageUrl() { return imageUrl; }
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
}

View File

@@ -25,6 +25,10 @@ public class ProductMapper {
dto.setPrice(price);
dto.setBuyUrl(buyUrl);
// product image
dto.setImageUrl(product.getMainImageUrl());
return dto;
}
}