mirror of
https://gitea.gofwd.group/Forward_Group/ballistic-builder-spring.git
synced 2025-12-06 02:56:44 -05:00
no idea?
This commit is contained in:
@@ -1,6 +1,17 @@
|
||||
package group.goforward.ballistic.imports;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.io.Reader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
|
||||
import group.goforward.ballistic.model.Brand;
|
||||
import group.goforward.ballistic.model.Merchant;
|
||||
@@ -34,66 +45,37 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
|
||||
Merchant merchant = merchantRepository.findById(merchantId)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Merchant not found: " + merchantId));
|
||||
|
||||
// For now, just pick a brand to prove inserts work (Aero Precision for merchant 4).
|
||||
// Later we can switch to row.brandName() + auto-create brands.
|
||||
Brand brand = brandRepository.findByNameIgnoreCase("Aero Precision")
|
||||
.orElseThrow(() -> new IllegalStateException("Brand 'Aero Precision' not found"));
|
||||
// Read all rows from the merchant feed
|
||||
List<MerchantFeedRow> rows = readFeedRowsForMerchant(merchant);
|
||||
System.out.println("IMPORT >>> read " + rows.size() + " rows for merchant=" + merchant.getName());
|
||||
|
||||
// TODO: replace this with real feed parsing:
|
||||
// List<MerchantFeedRow> rows = feedClient.fetch(merchant);
|
||||
// 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
|
||||
);
|
||||
for (MerchantFeedRow row : rows) {
|
||||
// Resolve brand from the row (fallback to "Aero Precision" or whatever you want as default)
|
||||
Brand brand = resolveBrand(row);
|
||||
Product p = upsertProduct(merchant, brand, row);
|
||||
|
||||
Product p = upsertProduct(merchant, brand, row);
|
||||
|
||||
System.out.println("IMPORT >>> upserted product id=" + p.getId()
|
||||
+ ", name=" + p.getName()
|
||||
+ ", slug=" + p.getSlug()
|
||||
+ ", platform=" + p.getPlatform()
|
||||
+ ", partRole=" + p.getPartRole()
|
||||
+ ", merchant=" + merchant.getName());
|
||||
System.out.println("IMPORT >>> upserted product id=" + p.getId()
|
||||
+ ", name=" + p.getName()
|
||||
+ ", slug=" + p.getSlug()
|
||||
+ ", platform=" + p.getPlatform()
|
||||
+ ", partRole=" + p.getPartRole()
|
||||
+ ", merchant=" + merchant.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
|
||||
*/
|
||||
// ---------------------------------------------------------------------
|
||||
// Upsert logic
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private Product upsertProduct(Merchant merchant, Brand brand, MerchantFeedRow row) {
|
||||
System.out.println("IMPORT >>> upsertProduct brand=" + brand.getName()
|
||||
+ ", sku=" + row.sku()
|
||||
+ ", productName=" + row.productName());
|
||||
|
||||
String mpn = trimOrNull(row.manufacturerId());
|
||||
String upc = trimOrNull(row.sku()); // later: real UPC column
|
||||
String upc = trimOrNull(row.sku()); // placeholder until real UPC field
|
||||
|
||||
java.util.List<Product> candidates = java.util.Collections.emptyList();
|
||||
List<Product> candidates = Collections.emptyList();
|
||||
|
||||
if (mpn != null) {
|
||||
candidates = productRepository.findAllByBrandAndMpn(brand, mpn);
|
||||
@@ -118,16 +100,10 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
|
||||
}
|
||||
|
||||
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(
|
||||
trimOrNull(row.productName()),
|
||||
@@ -158,7 +134,6 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
|
||||
slug = "product-" + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// Ensure slug is unique by appending a numeric suffix if needed
|
||||
String uniqueSlug = generateUniqueSlug(slug);
|
||||
p.setSlug(uniqueSlug);
|
||||
}
|
||||
@@ -176,15 +151,13 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
|
||||
p.setMainImageUrl(mainImage);
|
||||
|
||||
// ---------- IDENTIFIERS ----------
|
||||
// AvantLink "Manufacturer Id" is a good fit for MPN.
|
||||
String mpn = coalesce(
|
||||
trimOrNull(row.manufacturerId()),
|
||||
trimOrNull(row.sku())
|
||||
);
|
||||
p.setMpn(mpn);
|
||||
|
||||
// Feed doesn’t give us UPC in the header you showed.
|
||||
// We’ll leave UPC null for now (or map later).
|
||||
// UPC placeholder
|
||||
p.setUpc(null);
|
||||
|
||||
// ---------- PLATFORM ----------
|
||||
@@ -199,7 +172,100 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
|
||||
p.setPartRole(partRole);
|
||||
}
|
||||
|
||||
// --- Helpers ----------------------------------------------------------
|
||||
// ---------------------------------------------------------------------
|
||||
// Feed reading + brand resolution
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private List<MerchantFeedRow> readFeedRowsForMerchant(Merchant merchant) {
|
||||
String rawFeedUrl = merchant.getFeedUrl();
|
||||
if (rawFeedUrl == null || rawFeedUrl.isBlank()) {
|
||||
throw new IllegalStateException("Merchant " + merchant.getName() + " has no feed_url configured");
|
||||
}
|
||||
|
||||
String feedUrl = rawFeedUrl.trim();
|
||||
System.out.println("IMPORT >>> reading feed for merchant=" + merchant.getName() + " from: " + feedUrl);
|
||||
|
||||
List<MerchantFeedRow> rows = new ArrayList<>();
|
||||
|
||||
try (Reader reader = (feedUrl.startsWith("http://") || feedUrl.startsWith("https://"))
|
||||
? new InputStreamReader(new URL(feedUrl).openStream(), StandardCharsets.UTF_8)
|
||||
: java.nio.file.Files.newBufferedReader(java.nio.file.Paths.get(feedUrl), StandardCharsets.UTF_8);
|
||||
CSVParser parser = CSVFormat.DEFAULT
|
||||
.withFirstRecordAsHeader()
|
||||
.withIgnoreSurroundingSpaces()
|
||||
.withTrim()
|
||||
.parse(reader)) {
|
||||
|
||||
for (CSVRecord rec : parser) {
|
||||
MerchantFeedRow row = new MerchantFeedRow(
|
||||
rec.get("SKU"),
|
||||
rec.get("Manufacturer Id"),
|
||||
rec.get("Brand Name"),
|
||||
rec.get("Product Name"),
|
||||
rec.get("Long Description"),
|
||||
rec.get("Short Description"),
|
||||
rec.get("Department"),
|
||||
rec.get("Category"),
|
||||
rec.get("SubCategory"),
|
||||
rec.get("Thumb URL"),
|
||||
rec.get("Image URL"),
|
||||
rec.get("Buy Link"),
|
||||
rec.get("Keywords"),
|
||||
rec.get("Reviews"),
|
||||
parseBigDecimal(rec.get("Retail Price")),
|
||||
parseBigDecimal(rec.get("Sale Price")),
|
||||
rec.get("Brand Page Link"),
|
||||
rec.get("Brand Logo Image"),
|
||||
rec.get("Product Page View Tracking"),
|
||||
rec.get("Variants XML"),
|
||||
rec.get("Medium Image URL"),
|
||||
rec.get("Product Content Widget"),
|
||||
rec.get("Google Categorization"),
|
||||
rec.get("Item Based Commission")
|
||||
);
|
||||
|
||||
rows.add(row);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Failed to read feed for merchant "
|
||||
+ merchant.getName() + " from " + feedUrl, ex);
|
||||
}
|
||||
|
||||
System.out.println("IMPORT >>> parsed " + rows.size() + " rows for merchant=" + merchant.getName());
|
||||
return rows;
|
||||
}
|
||||
|
||||
private Brand resolveBrand(MerchantFeedRow row) {
|
||||
String rawBrand = trimOrNull(row.brandName());
|
||||
final String brandName = (rawBrand != null) ? rawBrand : "Aero Precision";
|
||||
|
||||
return brandRepository.findByNameIgnoreCase(brandName)
|
||||
.orElseGet(() -> {
|
||||
Brand b = new Brand();
|
||||
b.setName(brandName);
|
||||
return brandRepository.save(b);
|
||||
});
|
||||
}
|
||||
|
||||
private String getCol(String[] cols, int index) {
|
||||
return (index >= 0 && index < cols.length) ? cols[index] : null;
|
||||
}
|
||||
|
||||
private BigDecimal parseBigDecimal(String raw) {
|
||||
if (raw == null) return null;
|
||||
String trimmed = raw.trim();
|
||||
if (trimmed.isEmpty()) return null;
|
||||
try {
|
||||
return new BigDecimal(trimmed);
|
||||
} catch (NumberFormatException ex) {
|
||||
System.out.println("IMPORT !!! bad BigDecimal value: '" + raw + "', skipping");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Misc helpers
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private String trimOrNull(String value) {
|
||||
if (value == null) return null;
|
||||
@@ -236,7 +302,6 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
|
||||
if (lower.contains("ar-10") || lower.contains("ar10")) return "AR-10";
|
||||
if (lower.contains("ak-47") || lower.contains("ak47")) return "AK-47";
|
||||
|
||||
// Default: treat Aero as AR-15 universe for now
|
||||
return "AR-15";
|
||||
}
|
||||
|
||||
@@ -261,6 +326,9 @@ public class MerchantFeedImportServiceImpl implements MerchantFeedImportService
|
||||
if (lower.contains("lower")) {
|
||||
return "lower-receiver";
|
||||
}
|
||||
if (lower.contains("magazine") || lower.contains("mag")) {
|
||||
return "magazine";
|
||||
}
|
||||
if (lower.contains("stock") || lower.contains("buttstock")) {
|
||||
return "stock";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user