| 37337 |
amit |
1 |
package com.spice.profitmandi.web.offercircular;
|
|
|
2 |
|
|
|
3 |
import java.util.HashMap;
|
|
|
4 |
import java.util.Map;
|
|
|
5 |
import java.util.regex.Matcher;
|
|
|
6 |
import java.util.regex.Pattern;
|
|
|
7 |
|
|
|
8 |
import com.spice.profitmandi.dao.repository.offers.CircularIngestRepository;
|
|
|
9 |
|
|
|
10 |
/**
|
|
|
11 |
* Human-confirmed exceptions from offers.product_alias, consulted BEFORE any matching.
|
|
|
12 |
*
|
|
|
13 |
* These exist because the circular and our catalog sometimes name the same product
|
|
|
14 |
* differently - Apple ship "iPhone Air" while our catalog rows read "iPhone 17 Air" -
|
|
|
15 |
* and because some products are genuinely not ours (no Pixel SKUs are stocked). A
|
|
|
16 |
* confirmation recorded once keeps applying every following month, which is the whole
|
|
|
17 |
* point: without it the same review queue regenerates identically.
|
|
|
18 |
*/
|
|
|
19 |
public final class ProductAliases {
|
|
|
20 |
|
|
|
21 |
private static final Pattern VARIANT_SPEC = Pattern.compile(
|
|
|
22 |
"\\(?\\s*\\d+\\s*[+/]\\s*\\d+\\s*(?:GB|TB|G|T)?\\s*\\)?|\\d+\\s*(?:GB|TB)",
|
|
|
23 |
Pattern.CASE_INSENSITIVE);
|
|
|
24 |
|
|
|
25 |
public static final class Alias {
|
|
|
26 |
private final String action;
|
|
|
27 |
private final String canonicalText;
|
|
|
28 |
private final Integer catalogId;
|
|
|
29 |
private final Integer superCatalogId;
|
|
|
30 |
|
|
|
31 |
Alias(String action, String canonicalText, Integer catalogId, Integer superCatalogId) {
|
|
|
32 |
this.action = action;
|
|
|
33 |
this.canonicalText = canonicalText;
|
|
|
34 |
this.catalogId = catalogId;
|
|
|
35 |
this.superCatalogId = superCatalogId;
|
|
|
36 |
}
|
|
|
37 |
public boolean isIgnore() { return "IGNORE".equals(action); }
|
|
|
38 |
public boolean isPin() { return "PIN".equals(action) && (catalogId != null || superCatalogId != null); }
|
|
|
39 |
public boolean isRewrite() { return "REWRITE".equals(action) && canonicalText != null; }
|
|
|
40 |
public Integer getCatalogId() { return catalogId; }
|
|
|
41 |
public Integer getSuperCatalogId() { return superCatalogId; }
|
|
|
42 |
|
|
|
43 |
/**
|
|
|
44 |
* Substitutes the catalog's spelling while preserving whatever variant spec
|
|
|
45 |
* the circular gave, so "iPhone Air" becomes "iPhone 17 Air" and
|
|
|
46 |
* "RENO16C 12+256GB" would become "<canonical> 12+256GB".
|
|
|
47 |
*/
|
|
|
48 |
public String rewrite(String rawText) {
|
|
|
49 |
StringBuilder sb = new StringBuilder(canonicalText);
|
|
|
50 |
Matcher m = VARIANT_SPEC.matcher(rawText);
|
|
|
51 |
while (m.find()) {
|
|
|
52 |
sb.append(' ').append(m.group());
|
|
|
53 |
}
|
|
|
54 |
return sb.toString().trim();
|
|
|
55 |
}
|
|
|
56 |
}
|
|
|
57 |
|
|
|
58 |
private final Map<String, Alias> byLabelAndText = new HashMap<>();
|
|
|
59 |
|
|
|
60 |
private ProductAliases() { }
|
|
|
61 |
|
|
|
62 |
public static ProductAliases load(CircularIngestRepository repository) {
|
|
|
63 |
ProductAliases aliases = new ProductAliases();
|
|
|
64 |
for (Object[] row : repository.selectProductAliases()) {
|
|
|
65 |
String label = (String) row[0];
|
|
|
66 |
String rawText = (String) row[1];
|
|
|
67 |
String action = (String) row[2];
|
|
|
68 |
String canonical = (String) row[3];
|
|
|
69 |
int catalogId = ((Number) row[4]).intValue();
|
|
|
70 |
int superCatalogId = ((Number) row[5]).intValue();
|
|
|
71 |
aliases.byLabelAndText.put(key(label, rawText),
|
|
|
72 |
new Alias(action,
|
|
|
73 |
canonical == null || canonical.isEmpty() ? null : canonical,
|
|
|
74 |
catalogId == 0 ? null : catalogId,
|
|
|
75 |
superCatalogId == 0 ? null : superCatalogId));
|
|
|
76 |
}
|
|
|
77 |
return aliases;
|
|
|
78 |
}
|
|
|
79 |
|
|
|
80 |
/** Keyed on the normalised product text so trivial spacing differences still hit. */
|
|
|
81 |
private static String key(String divisionLabel, String rawText) {
|
|
|
82 |
return divisionLabel + "" + ProductNames.norm(rawText);
|
|
|
83 |
}
|
|
|
84 |
|
|
|
85 |
public Alias find(String divisionLabel, String rawText) {
|
|
|
86 |
return byLabelAndText.get(key(divisionLabel, rawText));
|
|
|
87 |
}
|
|
|
88 |
|
|
|
89 |
public int size() { return byLabelAndText.size(); }
|
|
|
90 |
}
|