small changes. still working

This commit is contained in:
2025-11-30 05:40:59 -05:00
parent 87b3c4bff8
commit f539c64588
2 changed files with 98 additions and 60 deletions

View File

@@ -1,6 +1,6 @@
package group.goforward.ballistic.imports;
import java.math.BigDecimal;
import java.util.Optional;
import group.goforward.ballistic.model.Brand;
import group.goforward.ballistic.model.Merchant;
@@ -41,37 +41,37 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
// TODO: replace this with real feed parsing:
// List<MerchantFeedRow> rows = feedClient.fetch(merchant);
// rows.forEach(row -> upsertProduct(merchant, row));
// rows.forEach(row -> upsertProduct(merchant, brand, row));
MerchantFeedRow row = new MerchantFeedRow(
"TEST-SKU-001",
"APPG100002",
brand.getName(),
"Test Product From Import",
"This is a long description from AvantLink.",
"Short description from AvantLink.",
"Rifles",
"AR-15 Parts",
"Handguards & Rails",
"https://example.com/thumb.jpg",
"https://example.com/image.jpg",
"https://example.com/buy-link",
"ar-15, handguard, aero",
null,
new BigDecimal("199.99"), // retailPrice
new BigDecimal("149.99"), // salePrice
null,
null,
null,
null,
"https://example.com/medium.jpg",
null,
null,
null
);
"TEST-SKU-001",
"APPG100002",
brand.getName(),
"Test Product From Import",
"This is a long description from AvantLink.",
"Short description from AvantLink.",
"Rifles",
"AR-15 Parts",
"Handguards & Rails",
"https://example.com/thumb.jpg",
"https://example.com/image.jpg",
"https://example.com/buy-link",
"ar-15, handguard, aero",
null,
new BigDecimal("199.99"), // retailPrice
new BigDecimal("149.99"), // salePrice
null,
null,
null,
null,
"https://example.com/medium.jpg",
null,
null,
null
);
Product p = createProduct(brand, row);
Product p = upsertProduct(merchant, brand, row);
System.out.println("IMPORT >>> created product id=" + p.getId()
System.out.println("IMPORT >>> upserted product id=" + p.getId()
+ ", name=" + p.getName()
+ ", slug=" + p.getSlug()
+ ", platform=" + p.getPlatform()
@@ -79,13 +79,54 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
+ ", merchant=" + merchant.getName());
}
private Product createProduct(Brand brand, MerchantFeedRow row) {
System.out.println("IMPORT >>> createProduct brand=" + brand.getName()
/**
* Upsert logic:
* - Try Brand+MPN, then Brand+UPC (for now using sku as a stand-in)
* - If found, update fields but keep existing slug
* - If not found, create a new Product and generate a unique slug
*/
private Product upsertProduct(Merchant merchant, Brand brand, MerchantFeedRow row) {
System.out.println("IMPORT >>> upsertProduct brand=" + brand.getName()
+ ", sku=" + row.sku()
+ ", productName=" + row.productName());
Product p = new Product();
p.setBrand(brand);
String mpn = trimOrNull(row.manufacturerId());
String upc = trimOrNull(row.sku()); // later: real UPC column
java.util.List<Product> candidates = java.util.Collections.emptyList();
if (mpn != null) {
candidates = productRepository.findAllByBrandAndMpn(brand, mpn);
}
if ((candidates == null || candidates.isEmpty()) && upc != null) {
candidates = productRepository.findAllByBrandAndUpc(brand, upc);
}
Product p;
boolean isNew = (candidates == null || candidates.isEmpty());
if (isNew) {
p = new Product();
p.setBrand(brand);
} else {
if (candidates.size() > 1) {
System.out.println("IMPORT !!! WARNING: multiple existing products found for brand="
+ brand.getName() + ", mpn=" + mpn + ", upc=" + upc
+ ". Using the first match (id=" + candidates.get(0).getId() + ")");
}
p = candidates.get(0);
}
updateProductFromRow(p, row, isNew);
return productRepository.save(p);
}
/**
* Shared mapping logic from feed row -> Product entity.
* If isNew = true, we generate a slug. Otherwise we leave the slug alone.
*/
private void updateProductFromRow(Product p, MerchantFeedRow row, boolean isNew) {
// ---------- NAME ----------
String name = coalesce(
@@ -100,25 +141,27 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
p.setName(name);
// ---------- SLUG ----------
String baseForSlug = coalesce(
trimOrNull(name),
trimOrNull(row.sku())
);
if (baseForSlug == null) {
baseForSlug = "product-" + System.currentTimeMillis();
}
if (isNew || p.getSlug() == null || p.getSlug().isBlank()) {
String baseForSlug = coalesce(
trimOrNull(name),
trimOrNull(row.sku())
);
if (baseForSlug == null) {
baseForSlug = "product-" + System.currentTimeMillis();
}
String slug = baseForSlug
.toLowerCase()
.replaceAll("[^a-z0-9]+", "-")
.replaceAll("(^-|-$)", "");
if (slug.isBlank()) {
slug = "product-" + System.currentTimeMillis();
}
String slug = baseForSlug
.toLowerCase()
.replaceAll("[^a-z0-9]+", "-")
.replaceAll("(^-|-$)", "");
if (slug.isBlank()) {
slug = "product-" + System.currentTimeMillis();
}
// Ensure slug is unique by appending a numeric suffix if needed
String uniqueSlug = generateUniqueSlug(slug);
p.setSlug(uniqueSlug);
// Ensure slug is unique by appending a numeric suffix if needed
String uniqueSlug = generateUniqueSlug(slug);
p.setSlug(uniqueSlug);
}
// ---------- DESCRIPTIONS ----------
p.setShortDescription(trimOrNull(row.shortDescription()));
@@ -141,24 +184,19 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
p.setMpn(mpn);
// Feed doesnt give us UPC in the header you showed.
// Well leave UPC null for now.
// Well leave UPC null for now (or map later).
p.setUpc(null);
// ---------- PLATFORM ----------
// For now, hard-code to AR-15 to satisfy not-null constraint.
// Later we can infer from row.category()/row.department().
String platform = inferPlatform(row);
p.setPlatform(platform != null ? platform : "AR-15");
// ---------- PART ROLE ----------
// We can do a tiny heuristic off category/subcategory.
String partRole = inferPartRole(row);
if (partRole == null || partRole.isBlank()) {
partRole = "unknown";
}
p.setPartRole(partRole);
return productRepository.save(p);
}
// --- Helpers ----------------------------------------------------------

View File

@@ -6,15 +6,15 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
import java.util.UUID;
import java.util.List;
public interface ProductRepository extends JpaRepository<Product, Integer> {
Optional<Product> findByUuid(UUID uuid);
Optional<Product> findByBrandAndMpn(Brand brand, String mpn);
Optional<Product> findByBrandAndUpc(Brand brand, String upc);
boolean existsBySlug(String slug);
List<Product> findAllByBrandAndMpn(Brand brand, String mpn);
List<Product> findAllByBrandAndUpc(Brand brand, String upc);
}