mirror of
https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
synced 2026-01-20 16:51:03 -05:00
fixed the duplicate mapping stuff.
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
package group.goforward.battlbuilder.controllers;
|
||||
|
||||
import group.goforward.battlbuilder.model.Merchant;
|
||||
import group.goforward.battlbuilder.model.MerchantCategoryMapping;
|
||||
import group.goforward.battlbuilder.repos.MerchantRepository;
|
||||
import group.goforward.battlbuilder.services.MerchantCategoryMappingService;
|
||||
import group.goforward.battlbuilder.web.dto.MerchantCategoryMappingDto;
|
||||
import group.goforward.battlbuilder.web.dto.UpsertMerchantCategoryMappingRequest;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/merchant-category-mappings")
|
||||
@CrossOrigin
|
||||
public class MerchantCategoryMappingController {
|
||||
|
||||
private final MerchantCategoryMappingService mappingService;
|
||||
private final MerchantRepository merchantRepository;
|
||||
|
||||
public MerchantCategoryMappingController(
|
||||
MerchantCategoryMappingService mappingService,
|
||||
MerchantRepository merchantRepository
|
||||
) {
|
||||
this.mappingService = mappingService;
|
||||
this.merchantRepository = merchantRepository;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<MerchantCategoryMappingDto> listMappings(
|
||||
@RequestParam("merchantId") Integer merchantId
|
||||
) {
|
||||
List<MerchantCategoryMapping> mappings = mappingService.findByMerchant(merchantId);
|
||||
return mappings.stream()
|
||||
.map(this::toDto)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public MerchantCategoryMappingDto upsertMapping(
|
||||
@RequestBody UpsertMerchantCategoryMappingRequest request
|
||||
) {
|
||||
Merchant merchant = merchantRepository
|
||||
.findById(request.getMerchantId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Merchant not found: " + request.getMerchantId()));
|
||||
|
||||
MerchantCategoryMapping mapping = mappingService.upsertMapping(
|
||||
merchant,
|
||||
request.getRawCategory(),
|
||||
request.getMappedPartRole()
|
||||
);
|
||||
|
||||
return toDto(mapping);
|
||||
}
|
||||
|
||||
private MerchantCategoryMappingDto toDto(MerchantCategoryMapping mapping) {
|
||||
MerchantCategoryMappingDto dto = new MerchantCategoryMappingDto();
|
||||
dto.setId(mapping.getId());
|
||||
dto.setMerchantId(mapping.getMerchant().getId());
|
||||
dto.setMerchantName(mapping.getMerchant().getName());
|
||||
dto.setRawCategory(mapping.getRawCategory());
|
||||
dto.setMappedPartRole(mapping.getMappedPartRole());
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package group.goforward.battlbuilder.controllers.admin;
|
||||
|
||||
import group.goforward.battlbuilder.model.CategoryMapping;
|
||||
import group.goforward.battlbuilder.model.Merchant;
|
||||
import group.goforward.battlbuilder.model.PartCategory;
|
||||
import group.goforward.battlbuilder.repos.CategoryMappingRepository;
|
||||
import group.goforward.battlbuilder.repos.PartCategoryRepository;
|
||||
import group.goforward.battlbuilder.web.dto.admin.MerchantCategoryMappingDto;
|
||||
import group.goforward.battlbuilder.web.dto.admin.SimpleMerchantDto;
|
||||
import group.goforward.battlbuilder.web.dto.admin.UpdateMerchantCategoryMappingRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/category-mappings")
|
||||
@CrossOrigin // tighten later
|
||||
public class AdminCategoryMappingController {
|
||||
|
||||
private final CategoryMappingRepository categoryMappingRepository;
|
||||
private final PartCategoryRepository partCategoryRepository;
|
||||
|
||||
public AdminCategoryMappingController(
|
||||
CategoryMappingRepository categoryMappingRepository,
|
||||
PartCategoryRepository partCategoryRepository
|
||||
) {
|
||||
this.categoryMappingRepository = categoryMappingRepository;
|
||||
this.partCategoryRepository = partCategoryRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merchants that have at least one category_mappings row.
|
||||
* Used for the "All Merchants" dropdown in the UI.
|
||||
*/
|
||||
@GetMapping("/merchants")
|
||||
public List<SimpleMerchantDto> listMerchantsWithMappings() {
|
||||
List<Merchant> merchants = categoryMappingRepository.findDistinctMerchantsWithMappings();
|
||||
return merchants.stream()
|
||||
.map(m -> new SimpleMerchantDto(m.getId(), m.getName()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* List mappings for a specific merchant, or all mappings if no merchantId is provided.
|
||||
* GET /api/admin/category-mappings?merchantId=1
|
||||
*/
|
||||
@GetMapping
|
||||
public List<MerchantCategoryMappingDto> listByMerchant(
|
||||
@RequestParam(name = "merchantId", required = false) Integer merchantId
|
||||
) {
|
||||
List<CategoryMapping> mappings;
|
||||
|
||||
if (merchantId != null) {
|
||||
mappings = categoryMappingRepository.findByMerchantIdOrderByRawCategoryPathAsc(merchantId);
|
||||
} else {
|
||||
mappings = categoryMappingRepository.findAll();
|
||||
}
|
||||
|
||||
return mappings.stream()
|
||||
.map(cm -> new MerchantCategoryMappingDto(
|
||||
cm.getId(),
|
||||
cm.getMerchant().getId(),
|
||||
cm.getMerchant().getName(),
|
||||
cm.getRawCategoryPath(),
|
||||
cm.getPartCategory() != null ? cm.getPartCategory().getId() : null,
|
||||
cm.getPartCategory() != null ? cm.getPartCategory().getName() : null
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a single mapping's part_category.
|
||||
* PUT /api/admin/category-mappings/{id}
|
||||
* Body: { "partCategoryId": 24 }
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public MerchantCategoryMappingDto updateMapping(
|
||||
@PathVariable Integer id,
|
||||
@RequestBody UpdateMerchantCategoryMappingRequest request
|
||||
) {
|
||||
CategoryMapping mapping = categoryMappingRepository.findById(id)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Mapping not found"));
|
||||
|
||||
PartCategory partCategory = null;
|
||||
if (request.partCategoryId() != null) {
|
||||
partCategory = partCategoryRepository.findById(request.partCategoryId())
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Part category not found"));
|
||||
}
|
||||
|
||||
mapping.setPartCategory(partCategory);
|
||||
mapping = categoryMappingRepository.save(mapping);
|
||||
|
||||
return new MerchantCategoryMappingDto(
|
||||
mapping.getId(),
|
||||
mapping.getMerchant().getId(),
|
||||
mapping.getMerchant().getName(),
|
||||
mapping.getRawCategoryPath(),
|
||||
mapping.getPartCategory() != null ? mapping.getPartCategory().getId() : null,
|
||||
mapping.getPartCategory() != null ? mapping.getPartCategory().getName() : null
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package group.goforward.battlbuilder.web;
|
||||
package group.goforward.battlbuilder.controllers.admin;
|
||||
|
||||
import group.goforward.battlbuilder.services.AdminDashboardService;
|
||||
import group.goforward.battlbuilder.services.admin.impl.AdminDashboardService;
|
||||
import group.goforward.battlbuilder.web.dto.AdminDashboardOverviewDto;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.time.OffsetDateTime;
|
||||
*/
|
||||
|
||||
@Entity
|
||||
@Table(name = "merchant_category_mappings")
|
||||
@Table(name = "merchant_category_map")
|
||||
public class MerchantCategoryMap {
|
||||
|
||||
@Id
|
||||
@@ -36,11 +36,11 @@ public class MerchantCategoryMap {
|
||||
@Column(name = "raw_category", nullable = false, length = Integer.MAX_VALUE)
|
||||
private String rawCategory;
|
||||
|
||||
@Column(name = "mapped_part_role", length = Integer.MAX_VALUE)
|
||||
private String mappedPartRole;
|
||||
@Column(name = "part_role", length = 255)
|
||||
private String partRole;
|
||||
|
||||
@Column(name = "mapped_configuration", length = Integer.MAX_VALUE)
|
||||
private String mappedConfiguration;
|
||||
// @Column(name = "mapped_configuration", length = Integer.MAX_VALUE)
|
||||
// private String mappedConfiguration;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "created_at", nullable = false)
|
||||
@@ -62,11 +62,11 @@ public class MerchantCategoryMap {
|
||||
public String getRawCategory() { return rawCategory; }
|
||||
public void setRawCategory(String rawCategory) { this.rawCategory = rawCategory; }
|
||||
|
||||
public String getMappedPartRole() { return mappedPartRole; }
|
||||
public void setMappedPartRole(String mappedPartRole) { this.mappedPartRole = mappedPartRole; }
|
||||
public String getPartRole() { return partRole; }
|
||||
public void setPartRole(String partRole) { this.partRole = partRole; }
|
||||
|
||||
public String getMappedConfiguration() { return mappedConfiguration; }
|
||||
public void setMappedConfiguration(String mappedConfiguration) { this.mappedConfiguration = mappedConfiguration; }
|
||||
// public String getMappedConfiguration() { return mappedConfiguration; }
|
||||
// public void setMappedConfiguration(String mappedConfiguration) { this.mappedConfiguration = mappedConfiguration; }
|
||||
|
||||
public OffsetDateTime getCreatedAt() { return createdAt; }
|
||||
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
package group.goforward.battlbuilder.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(
|
||||
name = "merchant_category_mappings",
|
||||
uniqueConstraints = @UniqueConstraint(
|
||||
name = "uq_merchant_category",
|
||||
columnNames = { "merchant_id", "raw_category" }
|
||||
)
|
||||
)
|
||||
public class MerchantCategoryMapping {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY) // SERIAL
|
||||
@Column(name = "id", nullable = false)
|
||||
private Integer id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, optional = false)
|
||||
@JoinColumn(name = "merchant_id", nullable = false)
|
||||
private Merchant merchant;
|
||||
|
||||
@Column(name = "raw_category", nullable = false, length = 512)
|
||||
private String rawCategory;
|
||||
|
||||
@Column(name = "mapped_part_role", length = 128)
|
||||
private String mappedPartRole; // e.g. "upper-receiver", "barrel"
|
||||
|
||||
@Column(name = "mapped_configuration")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ProductConfiguration mappedConfiguration;
|
||||
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private OffsetDateTime createdAt = OffsetDateTime.now();
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private OffsetDateTime updatedAt = OffsetDateTime.now();
|
||||
|
||||
@PreUpdate
|
||||
public void onUpdate() {
|
||||
this.updatedAt = OffsetDateTime.now();
|
||||
}
|
||||
|
||||
// getters & setters
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Merchant getMerchant() {
|
||||
return merchant;
|
||||
}
|
||||
|
||||
public void setMerchant(Merchant merchant) {
|
||||
this.merchant = merchant;
|
||||
}
|
||||
|
||||
public String getRawCategory() {
|
||||
return rawCategory;
|
||||
}
|
||||
|
||||
public void setRawCategory(String rawCategory) {
|
||||
this.rawCategory = rawCategory;
|
||||
}
|
||||
|
||||
public String getMappedPartRole() {
|
||||
return mappedPartRole;
|
||||
}
|
||||
|
||||
public void setMappedPartRole(String mappedPartRole) {
|
||||
this.mappedPartRole = mappedPartRole;
|
||||
}
|
||||
|
||||
public ProductConfiguration getMappedConfiguration() {
|
||||
return mappedConfiguration;
|
||||
}
|
||||
|
||||
public void setMappedConfiguration(ProductConfiguration mappedConfiguration) {
|
||||
this.mappedConfiguration = mappedConfiguration;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package group.goforward.battlbuilder.repos;
|
||||
|
||||
import group.goforward.battlbuilder.model.MerchantCategoryMap;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@@ -13,4 +15,9 @@ public interface MerchantCategoryMapRepository extends JpaRepository<MerchantCat
|
||||
Integer merchantId,
|
||||
String rawCategory
|
||||
);
|
||||
|
||||
Optional<MerchantCategoryMap> findFirstByMerchant_IdAndRawCategoryAndDeletedAtIsNull(
|
||||
Integer merchantId,
|
||||
String rawCategory
|
||||
);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package group.goforward.battlbuilder.repos;
|
||||
|
||||
import group.goforward.battlbuilder.model.Merchant;
|
||||
import group.goforward.battlbuilder.model.MerchantCategoryMapping;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface MerchantCategoryMappingRepository
|
||||
extends JpaRepository<MerchantCategoryMapping, Integer> {
|
||||
|
||||
Optional<MerchantCategoryMapping> findByMerchantIdAndRawCategoryIgnoreCase(
|
||||
Integer merchantId,
|
||||
String rawCategory
|
||||
);
|
||||
|
||||
Optional<MerchantCategoryMapping> findByMerchantIdAndRawCategory(
|
||||
Integer merchantId,
|
||||
String rawCategory
|
||||
);
|
||||
|
||||
List<MerchantCategoryMapping> findByMerchantIdOrderByRawCategoryAsc(Integer merchantId);
|
||||
|
||||
Optional<MerchantCategoryMapping> findByMerchantAndRawCategoryIgnoreCase(
|
||||
Merchant merchant,
|
||||
String rawCategory
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package group.goforward.battlbuilder.repos;
|
||||
|
||||
import aj.org.objectweb.asm.commons.Remapper;
|
||||
import group.goforward.battlbuilder.model.ImportStatus;
|
||||
import group.goforward.battlbuilder.model.Brand;
|
||||
import group.goforward.battlbuilder.model.Product;
|
||||
@@ -87,7 +86,7 @@ public interface ProductRepository extends JpaRepository<Product, Integer> {
|
||||
AND p.deletedAt IS NULL
|
||||
ORDER BY p.id
|
||||
""")
|
||||
List<Product> findTop5ByPlatformWithBrand(@Param("platform") String platform);
|
||||
List<Product> findByPlatformWithBrandOrdered(@Param("platform") String platform);
|
||||
|
||||
// -------------------------------------------------
|
||||
// Used by GunbuilderProductService (builder UI)
|
||||
@@ -178,45 +177,46 @@ public interface ProductRepository extends JpaRepository<Product, Integer> {
|
||||
// Mapping admin – pending buckets (all merchants)
|
||||
// -------------------------------------------------
|
||||
@Query("""
|
||||
SELECT m.id AS merchantId,
|
||||
m.name AS merchantName,
|
||||
p.rawCategoryKey AS rawCategoryKey,
|
||||
mcm.mappedPartRole AS mappedPartRole,
|
||||
COUNT(DISTINCT p.id) AS productCount
|
||||
FROM Product p
|
||||
JOIN p.offers o
|
||||
JOIN o.merchant m
|
||||
LEFT JOIN MerchantCategoryMapping mcm
|
||||
ON mcm.merchant.id = m.id
|
||||
AND mcm.rawCategory = p.rawCategoryKey
|
||||
WHERE p.importStatus = :status
|
||||
GROUP BY m.id, m.name, p.rawCategoryKey, mcm.mappedPartRole
|
||||
ORDER BY productCount DESC
|
||||
""")
|
||||
List<Object[]> findPendingMappingBuckets(
|
||||
@Param("status") ImportStatus status
|
||||
);
|
||||
SELECT m.id AS merchantId,
|
||||
m.name AS merchantName,
|
||||
p.rawCategoryKey AS rawCategoryKey,
|
||||
mcm.partRole AS mappedPartRole,
|
||||
COUNT(DISTINCT p.id) AS productCount
|
||||
FROM Product p
|
||||
JOIN p.offers o
|
||||
JOIN o.merchant m
|
||||
LEFT JOIN MerchantCategoryMap mcm
|
||||
ON mcm.merchant.id = m.id
|
||||
AND mcm.rawCategory = p.rawCategoryKey
|
||||
AND mcm.deletedAt IS NULL
|
||||
WHERE p.importStatus = :status
|
||||
GROUP BY m.id, m.name, p.rawCategoryKey, mcm.partRole
|
||||
ORDER BY productCount DESC
|
||||
""")
|
||||
List<Object[]> findPendingMappingBuckets(@Param("status") ImportStatus status);
|
||||
|
||||
|
||||
// -------------------------------------------------
|
||||
// Mapping admin – pending buckets for a single merchant
|
||||
// -------------------------------------------------
|
||||
@Query("""
|
||||
SELECT m.id AS merchantId,
|
||||
m.name AS merchantName,
|
||||
p.rawCategoryKey AS rawCategoryKey,
|
||||
mcm.mappedPartRole AS mappedPartRole,
|
||||
COUNT(DISTINCT p.id) AS productCount
|
||||
FROM Product p
|
||||
JOIN p.offers o
|
||||
JOIN o.merchant m
|
||||
LEFT JOIN MerchantCategoryMapping mcm
|
||||
ON mcm.merchant.id = m.id
|
||||
AND mcm.rawCategory = p.rawCategoryKey
|
||||
WHERE p.importStatus = :status
|
||||
AND m.id = :merchantId
|
||||
GROUP BY m.id, m.name, p.rawCategoryKey, mcm.mappedPartRole
|
||||
ORDER BY productCount DESC
|
||||
""")
|
||||
SELECT m.id AS merchantId,
|
||||
m.name AS merchantName,
|
||||
p.rawCategoryKey AS rawCategoryKey,
|
||||
mcm.partRole AS mappedPartRole,
|
||||
COUNT(DISTINCT p.id) AS productCount
|
||||
FROM Product p
|
||||
JOIN p.offers o
|
||||
JOIN o.merchant m
|
||||
LEFT JOIN MerchantCategoryMap mcm
|
||||
ON mcm.merchant.id = m.id
|
||||
AND mcm.rawCategory = p.rawCategoryKey
|
||||
AND mcm.deletedAt IS NULL
|
||||
WHERE p.importStatus = :status
|
||||
AND m.id = :merchantId
|
||||
GROUP BY m.id, m.name, p.rawCategoryKey, mcm.partRole
|
||||
ORDER BY productCount DESC
|
||||
""")
|
||||
List<Object[]> findPendingMappingBucketsForMerchant(
|
||||
@Param("merchantId") Integer merchantId,
|
||||
@Param("status") ImportStatus status
|
||||
|
||||
@@ -2,8 +2,8 @@ package group.goforward.battlbuilder.services;
|
||||
|
||||
import group.goforward.battlbuilder.model.ImportStatus;
|
||||
import group.goforward.battlbuilder.model.Merchant;
|
||||
import group.goforward.battlbuilder.model.MerchantCategoryMapping;
|
||||
import group.goforward.battlbuilder.repos.MerchantCategoryMappingRepository;
|
||||
import group.goforward.battlbuilder.model.MerchantCategoryMap;
|
||||
import group.goforward.battlbuilder.repos.MerchantCategoryMapRepository;
|
||||
import group.goforward.battlbuilder.repos.MerchantRepository;
|
||||
import group.goforward.battlbuilder.repos.ProductRepository;
|
||||
import group.goforward.battlbuilder.web.dto.PendingMappingBucketDto;
|
||||
@@ -16,28 +16,19 @@ import java.util.List;
|
||||
public class MappingAdminService {
|
||||
|
||||
private final ProductRepository productRepository;
|
||||
private final MerchantCategoryMappingRepository merchantCategoryMappingRepository;
|
||||
private final MerchantCategoryMapRepository merchantCategoryMapRepository;
|
||||
private final MerchantRepository merchantRepository;
|
||||
|
||||
public MappingAdminService(
|
||||
ProductRepository productRepository,
|
||||
MerchantCategoryMappingRepository merchantCategoryMappingRepository,
|
||||
MerchantCategoryMapRepository merchantCategoryMapRepository,
|
||||
MerchantRepository merchantRepository
|
||||
) {
|
||||
this.productRepository = productRepository;
|
||||
this.merchantCategoryMappingRepository = merchantCategoryMappingRepository;
|
||||
this.merchantCategoryMapRepository = merchantCategoryMapRepository;
|
||||
this.merchantRepository = merchantRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all pending mapping buckets across all merchants.
|
||||
* Each row is:
|
||||
* [0] merchantId (Integer)
|
||||
* [1] merchantName (String)
|
||||
* [2] rawCategoryKey (String)
|
||||
* [3] mappedPartRole (String, currently null from query)
|
||||
* [4] productCount (Long)
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public List<PendingMappingBucketDto> listPendingBuckets() {
|
||||
List<Object[]> rows = productRepository.findPendingMappingBuckets(
|
||||
@@ -63,10 +54,6 @@ public class MappingAdminService {
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies or updates a mapping for (merchant, rawCategoryKey) to a given partRole.
|
||||
* Does NOT retroactively update Product rows; they will be updated on the next import.
|
||||
*/
|
||||
@Transactional
|
||||
public void applyMapping(Integer merchantId, String rawCategoryKey, String mappedPartRole) {
|
||||
if (merchantId == null || rawCategoryKey == null || mappedPartRole == null || mappedPartRole.isBlank()) {
|
||||
@@ -76,18 +63,22 @@ public class MappingAdminService {
|
||||
Merchant merchant = merchantRepository.findById(merchantId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Merchant not found: " + merchantId));
|
||||
|
||||
MerchantCategoryMapping mapping = merchantCategoryMappingRepository
|
||||
.findByMerchantIdAndRawCategory(merchantId, rawCategoryKey)
|
||||
.orElseGet(() -> {
|
||||
MerchantCategoryMapping m = new MerchantCategoryMapping();
|
||||
m.setMerchant(merchant);
|
||||
m.setRawCategory(rawCategoryKey);
|
||||
return m;
|
||||
});
|
||||
List<MerchantCategoryMap> existing =
|
||||
merchantCategoryMapRepository.findAllByMerchant_IdAndRawCategoryAndDeletedAtIsNull(
|
||||
merchantId,
|
||||
rawCategoryKey
|
||||
);
|
||||
|
||||
mapping.setMappedPartRole(mappedPartRole.trim());
|
||||
merchantCategoryMappingRepository.save(mapping);
|
||||
MerchantCategoryMap mapping = existing.isEmpty()
|
||||
? new MerchantCategoryMap()
|
||||
: existing.get(0);
|
||||
|
||||
// Products will pick up this mapping on the next merchant import run.
|
||||
if (mapping.getId() == null) {
|
||||
mapping.setMerchant(merchant);
|
||||
mapping.setRawCategory(rawCategoryKey);
|
||||
}
|
||||
|
||||
mapping.setPartRole(mappedPartRole.trim());
|
||||
merchantCategoryMapRepository.save(mapping);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package group.goforward.battlbuilder.services;
|
||||
|
||||
import group.goforward.battlbuilder.model.Merchant;
|
||||
import group.goforward.battlbuilder.model.MerchantCategoryMapping;
|
||||
import group.goforward.battlbuilder.model.ProductConfiguration;
|
||||
import group.goforward.battlbuilder.repos.MerchantCategoryMappingRepository;
|
||||
import jakarta.transaction.Transactional;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class MerchantCategoryMappingService {
|
||||
|
||||
private final MerchantCategoryMappingRepository mappingRepository;
|
||||
|
||||
public MerchantCategoryMappingService(MerchantCategoryMappingRepository mappingRepository) {
|
||||
this.mappingRepository = mappingRepository;
|
||||
}
|
||||
|
||||
public List<MerchantCategoryMapping> findByMerchant(Integer merchantId) {
|
||||
return mappingRepository.findByMerchantIdOrderByRawCategoryAsc(merchantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve (or create) a mapping row for this merchant + raw category.
|
||||
* - If it exists, returns it (with whatever mappedPartRole / mappedConfiguration are set).
|
||||
* - If it doesn't exist, creates a placeholder row with null mappings and returns it.
|
||||
*
|
||||
* The importer can then:
|
||||
* - skip rows where mappedPartRole is still null
|
||||
* - use mappedConfiguration if present
|
||||
*/
|
||||
@Transactional
|
||||
public MerchantCategoryMapping resolveMapping(Merchant merchant, String rawCategory) {
|
||||
if (rawCategory == null || rawCategory.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String trimmed = rawCategory.trim();
|
||||
|
||||
return mappingRepository
|
||||
.findByMerchantIdAndRawCategoryIgnoreCase(merchant.getId(), trimmed)
|
||||
.orElseGet(() -> {
|
||||
MerchantCategoryMapping mapping = new MerchantCategoryMapping();
|
||||
mapping.setMerchant(merchant);
|
||||
mapping.setRawCategory(trimmed);
|
||||
mapping.setMappedPartRole(null);
|
||||
mapping.setMappedConfiguration(null);
|
||||
return mappingRepository.save(mapping);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Upsert mapping (admin UI).
|
||||
*/
|
||||
@Transactional
|
||||
public MerchantCategoryMapping upsertMapping(
|
||||
Merchant merchant,
|
||||
String rawCategory,
|
||||
String mappedPartRole,
|
||||
ProductConfiguration mappedConfiguration
|
||||
) {
|
||||
String trimmed = rawCategory.trim();
|
||||
|
||||
MerchantCategoryMapping mapping = mappingRepository
|
||||
.findByMerchantIdAndRawCategoryIgnoreCase(merchant.getId(), trimmed)
|
||||
.orElseGet(() -> {
|
||||
MerchantCategoryMapping m = new MerchantCategoryMapping();
|
||||
m.setMerchant(merchant);
|
||||
m.setRawCategory(trimmed);
|
||||
return m;
|
||||
});
|
||||
|
||||
mapping.setMappedPartRole(
|
||||
(mappedPartRole == null || mappedPartRole.isBlank()) ? null : mappedPartRole.trim()
|
||||
);
|
||||
|
||||
mapping.setMappedConfiguration(mappedConfiguration);
|
||||
|
||||
return mappingRepository.save(mapping);
|
||||
}
|
||||
/**
|
||||
* Backwards-compatible overload for existing callers (e.g. controller)
|
||||
* that don’t care about productConfiguration yet.
|
||||
*/
|
||||
@Transactional
|
||||
public MerchantCategoryMapping upsertMapping(
|
||||
Merchant merchant,
|
||||
String rawCategory,
|
||||
String mappedPartRole
|
||||
) {
|
||||
// Delegate to the new method with `null` configuration
|
||||
return upsertMapping(merchant, rawCategory, mappedPartRole, null);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package group.goforward.battlbuilder.services;
|
||||
package group.goforward.battlbuilder.services.admin.impl;
|
||||
|
||||
import group.goforward.battlbuilder.model.ImportStatus;
|
||||
import group.goforward.battlbuilder.repos.MerchantCategoryMappingRepository;
|
||||
import group.goforward.battlbuilder.repos.MerchantCategoryMapRepository;
|
||||
import group.goforward.battlbuilder.repos.MerchantRepository;
|
||||
import group.goforward.battlbuilder.repos.ProductRepository;
|
||||
import group.goforward.battlbuilder.web.dto.AdminDashboardOverviewDto;
|
||||
@@ -13,16 +13,16 @@ public class AdminDashboardService {
|
||||
|
||||
private final ProductRepository productRepository;
|
||||
private final MerchantRepository merchantRepository;
|
||||
private final MerchantCategoryMappingRepository merchantCategoryMappingRepository;
|
||||
private final MerchantCategoryMapRepository merchantCategoryMapRepository;
|
||||
|
||||
public AdminDashboardService(
|
||||
ProductRepository productRepository,
|
||||
MerchantRepository merchantRepository,
|
||||
MerchantCategoryMappingRepository merchantCategoryMappingRepository
|
||||
MerchantCategoryMapRepository merchantCategoryMapRepository
|
||||
) {
|
||||
this.productRepository = productRepository;
|
||||
this.merchantRepository = merchantRepository;
|
||||
this.merchantCategoryMappingRepository = merchantCategoryMappingRepository;
|
||||
this.merchantCategoryMapRepository = merchantCategoryMapRepository;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@@ -32,7 +32,7 @@ public class AdminDashboardService {
|
||||
long mappedProducts = totalProducts - unmappedProducts;
|
||||
|
||||
long merchantCount = merchantRepository.count();
|
||||
long categoryMappings = merchantCategoryMappingRepository.count();
|
||||
long categoryMappings = merchantCategoryMapRepository.count();
|
||||
|
||||
return new AdminDashboardOverviewDto(
|
||||
totalProducts,
|
||||
|
||||
@@ -65,7 +65,7 @@ public class CategoryClassificationServiceImpl implements CategoryClassification
|
||||
);
|
||||
|
||||
return mappings.stream()
|
||||
.map(MerchantCategoryMap::getMappedPartRole)
|
||||
.map(MerchantCategoryMap::getPartRole)
|
||||
.filter(r -> r != null && !r.isBlank())
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class ReclassificationServiceImpl implements ReclassificationService {
|
||||
);
|
||||
|
||||
return mappings.stream()
|
||||
.map(MerchantCategoryMap::getMappedPartRole)
|
||||
.map(MerchantCategoryMap::getPartRole)
|
||||
.filter(v -> v != null && !v.isBlank())
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package group.goforward.battlbuilder.web.admin;
|
||||
|
||||
import group.goforward.battlbuilder.services.MappingAdminService;
|
||||
import group.goforward.battlbuilder.web.dto.PendingMappingBucketDto;
|
||||
import group.goforward.battlbuilder.services.MappingAdminService;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package group.goforward.battlbuilder.web.admin;
|
||||
|
||||
import group.goforward.battlbuilder.services.MappingAdminService;
|
||||
import group.goforward.battlbuilder.web.dto.PendingMappingBucketDto;
|
||||
import group.goforward.battlbuilder.services.MappingAdminService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user