mirror of
https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
synced 2025-12-06 02:56:44 -05:00
expanded category grouping from db
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package group.goforward.ballistic.controllers.admin;
|
||||
|
||||
import group.goforward.ballistic.model.PartCategory;
|
||||
import group.goforward.ballistic.repos.PartCategoryRepository;
|
||||
import group.goforward.ballistic.web.dto.admin.PartCategoryDto;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/categories")
|
||||
@CrossOrigin
|
||||
public class AdminCategoryController {
|
||||
|
||||
private final PartCategoryRepository partCategories;
|
||||
|
||||
public AdminCategoryController(PartCategoryRepository partCategories) {
|
||||
this.partCategories = partCategories;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<PartCategoryDto> listCategories() {
|
||||
return partCategories.findAllByOrderByGroupNameAscSortOrderAscNameAsc()
|
||||
.stream()
|
||||
.map(this::toDto)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private PartCategoryDto toDto(PartCategory entity) {
|
||||
PartCategoryDto dto = new PartCategoryDto();
|
||||
dto.setId(entity.getId());
|
||||
dto.setSlug(entity.getSlug());
|
||||
dto.setName(entity.getName());
|
||||
dto.setDescription(entity.getDescription());
|
||||
dto.setGroupName(entity.getGroupName());
|
||||
dto.setSortOrder(entity.getSortOrder());
|
||||
dto.setUuid(entity.getUuid());
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,27 @@ import jakarta.persistence.*;
|
||||
@Entity
|
||||
@Table(name = "affiliate_category_map")
|
||||
public class AffiliateCategoryMap {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", nullable = false)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "feedname", nullable = false, length = 100)
|
||||
private String feedname;
|
||||
// e.g. "PART_ROLE"
|
||||
@Column(name = "source_type", nullable = false)
|
||||
private String sourceType;
|
||||
|
||||
@Column(name = "affiliatecategory", nullable = false)
|
||||
private String affiliatecategory;
|
||||
// e.g. "suppressor"
|
||||
@Column(name = "source_value", nullable = false)
|
||||
private String sourceValue;
|
||||
|
||||
@Column(name = "buildercategoryid", nullable = false)
|
||||
private Integer buildercategoryid;
|
||||
// e.g. "AR-15", nullable
|
||||
@Column(name = "platform")
|
||||
private String platform;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "part_category_id", nullable = false)
|
||||
private PartCategory partCategory;
|
||||
|
||||
@Column(name = "notes")
|
||||
private String notes;
|
||||
@@ -30,28 +38,36 @@ public class AffiliateCategoryMap {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFeedname() {
|
||||
return feedname;
|
||||
public String getSourceType() {
|
||||
return sourceType;
|
||||
}
|
||||
|
||||
public void setFeedname(String feedname) {
|
||||
this.feedname = feedname;
|
||||
public void setSourceType(String sourceType) {
|
||||
this.sourceType = sourceType;
|
||||
}
|
||||
|
||||
public String getAffiliatecategory() {
|
||||
return affiliatecategory;
|
||||
public String getSourceValue() {
|
||||
return sourceValue;
|
||||
}
|
||||
|
||||
public void setAffiliatecategory(String affiliatecategory) {
|
||||
this.affiliatecategory = affiliatecategory;
|
||||
public void setSourceValue(String sourceValue) {
|
||||
this.sourceValue = sourceValue;
|
||||
}
|
||||
|
||||
public Integer getBuildercategoryid() {
|
||||
return buildercategoryid;
|
||||
public String getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public void setBuildercategoryid(Integer buildercategoryid) {
|
||||
this.buildercategoryid = buildercategoryid;
|
||||
public void setPlatform(String platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
public PartCategory getPartCategory() {
|
||||
return partCategory;
|
||||
}
|
||||
|
||||
public void setPartCategory(PartCategory partCategory) {
|
||||
this.partCategory = partCategory;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
@@ -61,5 +77,4 @@ public class AffiliateCategoryMap {
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,49 @@
|
||||
package group.goforward.ballistic.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import org.hibernate.annotations.ColumnDefault;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "part_categories")
|
||||
public class PartCategory {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", nullable = false)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "slug", nullable = false, length = Integer.MAX_VALUE)
|
||||
@Column(name = "slug", nullable = false, unique = true)
|
||||
private String slug;
|
||||
|
||||
@Column(name = "name", nullable = false, length = Integer.MAX_VALUE)
|
||||
@Column(name = "name", nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", length = Integer.MAX_VALUE)
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@ColumnDefault("gen_random_uuid()")
|
||||
@Column(name = "uuid", nullable = false)
|
||||
private UUID uuid;
|
||||
|
||||
@Column(name = "group_name")
|
||||
private String groupName;
|
||||
|
||||
@Column(name = "sort_order")
|
||||
private Integer sortOrder;
|
||||
|
||||
@ColumnDefault("now()")
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@ColumnDefault("now()")
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
// --- Getters & Setters ---
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -51,4 +76,43 @@ public class PartCategory {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public void setGroupName(String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
|
||||
public Integer getSortOrder() {
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
public void setSortOrder(Integer sortOrder) {
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public OffsetDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(OffsetDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public OffsetDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(OffsetDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package group.goforward.ballistic.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "part_role_category_mappings",
|
||||
uniqueConstraints = @UniqueConstraint(columnNames = {"platform", "part_role"}))
|
||||
public class PartRoleCategoryMapping {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "platform", nullable = false)
|
||||
private String platform;
|
||||
|
||||
@Column(name = "part_role", nullable = false)
|
||||
private String partRole;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "category_slug", referencedColumnName = "slug", nullable = false)
|
||||
private PartCategory category;
|
||||
|
||||
@Column(name = "notes")
|
||||
private String notes;
|
||||
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private OffsetDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private OffsetDateTime updatedAt;
|
||||
|
||||
// getters/setters…
|
||||
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public String getPlatform() { return platform; }
|
||||
public void setPlatform(String platform) { this.platform = platform; }
|
||||
|
||||
public String getPartRole() { return partRole; }
|
||||
public void setPartRole(String partRole) { this.partRole = partRole; }
|
||||
|
||||
public PartCategory getCategory() { return category; }
|
||||
public void setCategory(PartCategory category) { this.category = category; }
|
||||
|
||||
public String getNotes() { return notes; }
|
||||
public void setNotes(String notes) { this.notes = notes; }
|
||||
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||
|
||||
public OffsetDateTime getUpdatedAt() { return updatedAt; }
|
||||
public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; }
|
||||
}
|
||||
@@ -3,7 +3,13 @@ package group.goforward.ballistic.model;
|
||||
import jakarta.persistence.*;
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
import group.goforward.ballistic.model.ProductOffer;
|
||||
import group.goforward.ballistic.model.ProductConfiguration;
|
||||
|
||||
@Entity
|
||||
@@ -68,7 +74,16 @@ public class Product {
|
||||
@Column(name = "platform_locked", nullable = false)
|
||||
private Boolean platformLocked = false;
|
||||
|
||||
|
||||
@OneToMany(mappedBy = "product", fetch = FetchType.LAZY)
|
||||
private Set<ProductOffer> offers = new HashSet<>();
|
||||
|
||||
public Set<ProductOffer> getOffers() {
|
||||
return offers;
|
||||
}
|
||||
|
||||
public void setOffers(Set<ProductOffer> offers) {
|
||||
this.offers = offers;
|
||||
}
|
||||
|
||||
// --- lifecycle hooks ---
|
||||
|
||||
@@ -236,4 +251,41 @@ public class Product {
|
||||
public void setConfiguration(ProductConfiguration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
// Convenience: best offer price for Gunbuilder
|
||||
public BigDecimal getBestOfferPrice() {
|
||||
if (offers == null || offers.isEmpty()) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
return offers.stream()
|
||||
// pick sale_price if present, otherwise retail_price
|
||||
.map(offer -> {
|
||||
if (offer.getSalePrice() != null) {
|
||||
return offer.getSalePrice();
|
||||
}
|
||||
return offer.getRetailPrice();
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.min(BigDecimal::compareTo)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
// Convenience: URL for the best-priced offer
|
||||
public String getBestOfferBuyUrl() {
|
||||
if (offers == null || offers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return offers.stream()
|
||||
.sorted(Comparator.comparing(offer -> {
|
||||
if (offer.getSalePrice() != null) {
|
||||
return offer.getSalePrice();
|
||||
}
|
||||
return offer.getRetailPrice();
|
||||
}, Comparator.nullsLast(BigDecimal::compareTo)))
|
||||
.map(ProductOffer::getAffiliateUrl)
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ import org.hibernate.annotations.OnDeleteAction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
@Entity
|
||||
@Table(name = "product_offers")
|
||||
public class ProductOffer {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", nullable = false)
|
||||
@@ -26,16 +26,16 @@ public class ProductOffer {
|
||||
@JoinColumn(name = "merchant_id", nullable = false)
|
||||
private Merchant merchant;
|
||||
|
||||
@Column(name = "avantlink_product_id", nullable = false, length = Integer.MAX_VALUE)
|
||||
@Column(name = "avantlink_product_id", nullable = false)
|
||||
private String avantlinkProductId;
|
||||
|
||||
@Column(name = "sku", length = Integer.MAX_VALUE)
|
||||
@Column(name = "sku")
|
||||
private String sku;
|
||||
|
||||
@Column(name = "upc", length = Integer.MAX_VALUE)
|
||||
@Column(name = "upc")
|
||||
private String upc;
|
||||
|
||||
@Column(name = "buy_url", nullable = false, length = Integer.MAX_VALUE)
|
||||
@Column(name = "buy_url", nullable = false)
|
||||
private String buyUrl;
|
||||
|
||||
@Column(name = "price", nullable = false, precision = 10, scale = 2)
|
||||
@@ -45,7 +45,7 @@ public class ProductOffer {
|
||||
private BigDecimal originalPrice;
|
||||
|
||||
@ColumnDefault("'USD'")
|
||||
@Column(name = "currency", nullable = false, length = Integer.MAX_VALUE)
|
||||
@Column(name = "currency", nullable = false)
|
||||
private String currency;
|
||||
|
||||
@ColumnDefault("true")
|
||||
@@ -60,6 +60,10 @@ public class ProductOffer {
|
||||
@Column(name = "first_seen_at", nullable = false)
|
||||
private OffsetDateTime firstSeenAt;
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Getters & setters
|
||||
// -----------------------------------------------------
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
@@ -164,14 +168,26 @@ public class ProductOffer {
|
||||
this.firstSeenAt = firstSeenAt;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Helper Methods (used by Product entity)
|
||||
// -----------------------------------------------------
|
||||
|
||||
public BigDecimal getSalePrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public BigDecimal getRetailPrice() {
|
||||
return originalPrice != null ? originalPrice : price;
|
||||
}
|
||||
|
||||
public String getAffiliateUrl() {
|
||||
return buyUrl;
|
||||
}
|
||||
|
||||
public BigDecimal getEffectivePrice() {
|
||||
// Prefer a true sale price when it's lower than the original
|
||||
if (price != null && originalPrice != null && price.compareTo(originalPrice) < 0) {
|
||||
return price;
|
||||
}
|
||||
|
||||
// Otherwise, use whatever is available
|
||||
return price != null ? price : originalPrice;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,5 +3,18 @@ package group.goforward.ballistic.repos;
|
||||
import group.goforward.ballistic.model.AffiliateCategoryMap;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CategoryMappingRepository extends JpaRepository<AffiliateCategoryMap, Integer> {
|
||||
|
||||
Optional<AffiliateCategoryMap> findBySourceTypeAndSourceValueAndPlatformIgnoreCase(
|
||||
String sourceType,
|
||||
String sourceValue,
|
||||
String platform
|
||||
);
|
||||
|
||||
Optional<AffiliateCategoryMap> findBySourceTypeAndSourceValueIgnoreCase(
|
||||
String sourceType,
|
||||
String sourceValue
|
||||
);
|
||||
}
|
||||
@@ -2,8 +2,13 @@ package group.goforward.ballistic.repos;
|
||||
|
||||
import group.goforward.ballistic.model.PartCategory;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface PartCategoryRepository extends JpaRepository<PartCategory, Integer> {
|
||||
|
||||
Optional<PartCategory> findBySlug(String slug);
|
||||
|
||||
List<PartCategory> findAllByOrderByGroupNameAscSortOrderAscNameAsc();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package group.goforward.ballistic.repos;
|
||||
|
||||
import group.goforward.ballistic.model.PartRoleCategoryMapping;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface PartRoleCategoryMappingRepository extends JpaRepository<PartRoleCategoryMapping, Integer> {
|
||||
|
||||
List<PartRoleCategoryMapping> findAllByPlatformOrderByPartRoleAsc(String platform);
|
||||
|
||||
Optional<PartRoleCategoryMapping> findByPlatformAndPartRole(String platform, String partRole);
|
||||
}
|
||||
@@ -1,33 +1,28 @@
|
||||
package group.goforward.ballistic.repos;
|
||||
|
||||
import group.goforward.ballistic.model.Product;
|
||||
import group.goforward.ballistic.model.Brand;
|
||||
import group.goforward.ballistic.model.Product;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.List;
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ProductRepository extends JpaRepository<Product, Integer> {
|
||||
|
||||
Optional<Product> findByUuid(UUID uuid);
|
||||
|
||||
boolean existsBySlug(String slug);
|
||||
// -------------------------------------------------
|
||||
// Used by MerchantFeedImportServiceImpl
|
||||
// -------------------------------------------------
|
||||
|
||||
List<Product> findAllByBrandAndMpn(Brand brand, String mpn);
|
||||
|
||||
List<Product> findAllByBrandAndUpc(Brand brand, String upc);
|
||||
|
||||
// All products for a given platform (e.g. "AR-15")
|
||||
List<Product> findByPlatform(String platform);
|
||||
boolean existsBySlug(String slug);
|
||||
|
||||
// Products filtered by platform + part roles (e.g. upper-receiver, barrel, etc.)
|
||||
List<Product> findByPlatformAndPartRoleIn(String platform, Collection<String> partRoles);
|
||||
|
||||
// ---------- Optimized variants for Gunbuilder (fetch brand to avoid N+1) ----------
|
||||
// -------------------------------------------------
|
||||
// Used by ProductController for platform views
|
||||
// -------------------------------------------------
|
||||
|
||||
@Query("""
|
||||
SELECT p
|
||||
@@ -43,11 +38,25 @@ public interface ProductRepository extends JpaRepository<Product, Integer> {
|
||||
FROM Product p
|
||||
JOIN FETCH p.brand b
|
||||
WHERE p.platform = :platform
|
||||
AND p.partRole IN :partRoles
|
||||
AND p.partRole IN :roles
|
||||
AND p.deletedAt IS NULL
|
||||
""")
|
||||
List<Product> findByPlatformAndPartRoleInWithBrand(
|
||||
@Param("platform") String platform,
|
||||
@Param("partRoles") Collection<String> partRoles
|
||||
@Param("roles") List<String> roles
|
||||
);
|
||||
|
||||
// -------------------------------------------------
|
||||
// Used by Gunbuilder service (if you wired this)
|
||||
// -------------------------------------------------
|
||||
|
||||
@Query("""
|
||||
SELECT DISTINCT p
|
||||
FROM Product p
|
||||
LEFT JOIN FETCH p.brand b
|
||||
LEFT JOIN FETCH p.offers o
|
||||
WHERE p.platform = :platform
|
||||
AND p.deletedAt IS NULL
|
||||
""")
|
||||
List<Product> findSomethingForGunbuilder(@Param("platform") String platform);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package group.goforward.ballistic.services;
|
||||
|
||||
import group.goforward.ballistic.model.PartCategory;
|
||||
import group.goforward.ballistic.model.Product;
|
||||
import group.goforward.ballistic.repos.ProductRepository;
|
||||
import group.goforward.ballistic.web.dto.GunbuilderProductDto;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class GunbuilderProductService {
|
||||
|
||||
private final ProductRepository productRepository;
|
||||
private final PartCategoryResolverService partCategoryResolverService;
|
||||
|
||||
public GunbuilderProductService(
|
||||
ProductRepository productRepository,
|
||||
PartCategoryResolverService partCategoryResolverService
|
||||
) {
|
||||
this.productRepository = productRepository;
|
||||
this.partCategoryResolverService = partCategoryResolverService;
|
||||
}
|
||||
|
||||
public List<GunbuilderProductDto> listGunbuilderProducts(String platform) {
|
||||
|
||||
List<Product> products = productRepository.findSomethingForGunbuilder(platform);
|
||||
|
||||
return products.stream()
|
||||
.map(p -> {
|
||||
var maybeCategory = partCategoryResolverService
|
||||
.resolveForPlatformAndPartRole(platform, p.getPartRole());
|
||||
|
||||
if (maybeCategory.isEmpty()) {
|
||||
// you can also log here
|
||||
return null;
|
||||
}
|
||||
|
||||
PartCategory cat = maybeCategory.get();
|
||||
|
||||
return new GunbuilderProductDto(
|
||||
p.getId(),
|
||||
p.getName(),
|
||||
p.getBrand().getName(),
|
||||
platform,
|
||||
p.getPartRole(),
|
||||
p.getBestOfferPrice(),
|
||||
p.getMainImageUrl(),
|
||||
p.getBestOfferBuyUrl(),
|
||||
cat.getSlug(),
|
||||
cat.getGroupName()
|
||||
);
|
||||
})
|
||||
.filter(dto -> dto != null)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package group.goforward.ballistic.services;
|
||||
|
||||
import group.goforward.ballistic.model.AffiliateCategoryMap;
|
||||
import group.goforward.ballistic.model.PartCategory;
|
||||
import group.goforward.ballistic.repos.CategoryMappingRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class PartCategoryResolverService {
|
||||
|
||||
private final CategoryMappingRepository categoryMappingRepository;
|
||||
|
||||
public PartCategoryResolverService(CategoryMappingRepository categoryMappingRepository) {
|
||||
this.categoryMappingRepository = categoryMappingRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a part category from a platform + partRole (what gunbuilder cares about).
|
||||
* Returns Optional.empty() if we have no mapping yet.
|
||||
*/
|
||||
public Optional<PartCategory> resolveForPlatformAndPartRole(String platform, String partRole) {
|
||||
// sourceType is a convention – you can also enum this
|
||||
String sourceType = "PART_ROLE";
|
||||
|
||||
// First try with platform
|
||||
return categoryMappingRepository
|
||||
.findBySourceTypeAndSourceValueAndPlatformIgnoreCase(sourceType, partRole, platform)
|
||||
.map(AffiliateCategoryMap::getPartCategory)
|
||||
// if that fails, fall back to ANY platform
|
||||
.or(() ->
|
||||
categoryMappingRepository
|
||||
.findBySourceTypeAndSourceValueIgnoreCase(sourceType, partRole)
|
||||
.map(AffiliateCategoryMap::getPartCategory)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package group.goforward.ballistic.web.dto;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class GunbuilderProductDto {
|
||||
|
||||
private Integer id;
|
||||
private String name;
|
||||
private String brand;
|
||||
private String platform;
|
||||
private String partRole;
|
||||
private BigDecimal price;
|
||||
private String imageUrl;
|
||||
private String buyUrl;
|
||||
private String categorySlug;
|
||||
private String categoryGroup;
|
||||
|
||||
public GunbuilderProductDto(
|
||||
Integer id,
|
||||
String name,
|
||||
String brand,
|
||||
String platform,
|
||||
String partRole,
|
||||
BigDecimal price,
|
||||
String imageUrl,
|
||||
String buyUrl,
|
||||
String categorySlug,
|
||||
String categoryGroup
|
||||
) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.brand = brand;
|
||||
this.platform = platform;
|
||||
this.partRole = partRole;
|
||||
this.price = price;
|
||||
this.imageUrl = imageUrl;
|
||||
this.buyUrl = buyUrl;
|
||||
this.categorySlug = categorySlug;
|
||||
this.categoryGroup = categoryGroup;
|
||||
}
|
||||
|
||||
// --- Getters only (DTOs are read-only in most cases) ---
|
||||
public Integer getId() { return id; }
|
||||
public String getName() { return name; }
|
||||
public String getBrand() { return brand; }
|
||||
public String getPlatform() { return platform; }
|
||||
public String getPartRole() { return partRole; }
|
||||
public BigDecimal getPrice() { return price; }
|
||||
public String getImageUrl() { return imageUrl; }
|
||||
public String getBuyUrl() { return buyUrl; }
|
||||
public String getCategorySlug() { return categorySlug; }
|
||||
public String getCategoryGroup() { return categoryGroup; }
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package group.goforward.ballistic.web.dto.admin;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PartCategoryDto {
|
||||
private Integer id;
|
||||
private String slug;
|
||||
private String name;
|
||||
private String description;
|
||||
private String groupName;
|
||||
private Integer sortOrder;
|
||||
private UUID uuid;
|
||||
|
||||
// getters + setters
|
||||
public Integer getId() { return id; }
|
||||
public void setId(Integer id) { this.id = id; }
|
||||
|
||||
public String getSlug() { return slug; }
|
||||
public void setSlug(String slug) { this.slug = slug; }
|
||||
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getGroupName() { return groupName; }
|
||||
public void setGroupName(String groupName) { this.groupName = groupName; }
|
||||
|
||||
public Integer getSortOrder() { return sortOrder; }
|
||||
public void setSortOrder(Integer sortOrder) { this.sortOrder = sortOrder; }
|
||||
|
||||
public UUID getUuid() { return uuid; }
|
||||
public void setUuid(UUID uuid) { this.uuid = uuid; }
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package group.goforward.ballistic.web.dto.admin;
|
||||
|
||||
public class PartRoleMappingDto {
|
||||
private Integer id;
|
||||
private String platform;
|
||||
private String partRole;
|
||||
private String categorySlug;
|
||||
private String categoryName;
|
||||
private String groupName;
|
||||
private String notes;
|
||||
|
||||
// getters + setters...
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public void setPlatform(String platform) {
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
public String getPartRole() {
|
||||
return partRole;
|
||||
}
|
||||
|
||||
public void setPartRole(String partRole) {
|
||||
this.partRole = partRole;
|
||||
}
|
||||
|
||||
public String getCategorySlug() {
|
||||
return categorySlug;
|
||||
}
|
||||
|
||||
public void setCategorySlug(String categorySlug) {
|
||||
this.categorySlug = categorySlug;
|
||||
}
|
||||
|
||||
public String getCategoryName() {
|
||||
return categoryName;
|
||||
}
|
||||
|
||||
public void setCategoryName(String categoryName) {
|
||||
this.categoryName = categoryName;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public void setGroupName(String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user