Subversion Repositories SmartDukaan

Rev

Rev 37337 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 37337 Rev 37526
Line 41... Line 41...
41
        private final boolean keep;
41
        private final boolean keep;
42
        private final String reason;
42
        private final String reason;
43
        private final String brand;
43
        private final String brand;
44
        private final int categoryId;
44
        private final int categoryId;
45
        private final List<Pattern> includeOnly;
45
        private final List<Pattern> includeOnly;
-
 
46
        private final String canonicalLabel;
46
 
47
 
47
        private Decision(boolean keep, String reason, String brand, int categoryId,
48
        private Decision(boolean keep, String reason, String brand, int categoryId,
48
                         List<Pattern> includeOnly) {
49
                         List<Pattern> includeOnly, String canonicalLabel) {
49
            this.keep = keep;
50
            this.keep = keep;
50
            this.reason = reason;
51
            this.reason = reason;
51
            this.brand = brand;
52
            this.brand = brand;
52
            this.categoryId = categoryId;
53
            this.categoryId = categoryId;
53
            this.includeOnly = includeOnly;
54
            this.includeOnly = includeOnly;
-
 
55
            this.canonicalLabel = canonicalLabel;
54
        }
56
        }
55
        public boolean isKeep() { return keep; }
57
        public boolean isKeep() { return keep; }
56
        public String getReason() { return reason; }
58
        public String getReason() { return reason; }
57
        public String getBrand() { return brand; }
59
        public String getBrand() { return brand; }
58
        public int getCategoryId() { return categoryId; }
60
        public int getCategoryId() { return categoryId; }
59
 
61
 
-
 
62
        /**
-
 
63
         * The division's own label, with any alias already resolved. Everything that
-
 
64
         * looks a division up by name must use THIS and not the label the PDF printed -
-
 
65
         * see CircularIngestRepository.selectDivisionAliases for what goes wrong
-
 
66
         * otherwise.
-
 
67
         */
-
 
68
        public String getCanonicalLabel() { return canonicalLabel; }
-
 
69
 
60
        /** Drops entities that no INCLUDE_ONLY rule accepts (Apple -> iPhone only). */
70
        /** Drops entities that no INCLUDE_ONLY rule accepts (Apple -> iPhone only). */
61
        public List<String> filterEntities(List<String> entities) {
71
        public List<String> filterEntities(List<String> entities) {
62
            if (includeOnly == null || includeOnly.isEmpty()) {
72
            if (includeOnly == null || includeOnly.isEmpty()) {
63
                return entities;
73
                return entities;
64
            }
74
            }
Line 76... Line 86...
76
    }
86
    }
77
 
87
 
78
    private final Map<String, Division> divisions = new LinkedHashMap<>();
88
    private final Map<String, Division> divisions = new LinkedHashMap<>();
79
    private final Map<String, List<Rule>> rules = new LinkedHashMap<>();
89
    private final Map<String, List<Rule>> rules = new LinkedHashMap<>();
80
    private final Map<String, String> brandByLabel = new LinkedHashMap<>();
90
    private final Map<String, String> brandByLabel = new LinkedHashMap<>();
-
 
91
    /** alias label -> the division's own label. Never the other way round. */
-
 
92
    private final Map<String, String> aliases = new LinkedHashMap<>();
81
 
93
 
82
    private ScopeConfig() { }
94
    private ScopeConfig() { }
83
 
95
 
84
    public static ScopeConfig load(CircularIngestRepository repository) {
96
    public static ScopeConfig load(CircularIngestRepository repository) {
85
        ScopeConfig config = new ScopeConfig();
97
        ScopeConfig config = new ScopeConfig();
Line 91... Line 103...
91
            String brand = row.length > 3 && row[3] != null ? (String) row[3] : "";
103
            String brand = row.length > 3 && row[3] != null ? (String) row[3] : "";
92
            if (!brand.isEmpty()) {
104
            if (!brand.isEmpty()) {
93
                config.brandByLabel.put(label, brand);
105
                config.brandByLabel.put(label, brand);
94
            }
106
            }
95
        }
107
        }
-
 
108
        for (Object[] row : repository.selectDivisionAliases()) {
-
 
109
            String alias = (String) row[0];
-
 
110
            String target = (String) row[1];
-
 
111
            // A label that is a division in its own right must never be shadowed by an
-
 
112
            // alias - it would resolve two ways and which won would depend on load order.
-
 
113
            // The controller refuses to save such an alias; this is the second guard, for
-
 
114
            // rows that predate it or were inserted by hand.
-
 
115
            if (alias == null || target == null || config.divisions.containsKey(alias)) {
-
 
116
                continue;
-
 
117
            }
-
 
118
            config.aliases.put(alias, target);
-
 
119
        }
96
        for (Object[] row : repository.selectScopeRules()) {
120
        for (Object[] row : repository.selectScopeRules()) {
97
            String label = row[0] == null ? "" : (String) row[0];
121
            String label = row[0] == null ? "" : (String) row[0];
98
            config.rules.computeIfAbsent(label, k -> new ArrayList<>())
122
            config.rules.computeIfAbsent(label, k -> new ArrayList<>())
99
                    .add(new Rule((String) row[1],
123
                    .add(new Rule((String) row[1],
100
                            Pattern.compile((String) row[2], Pattern.CASE_INSENSITIVE)));
124
                            Pattern.compile((String) row[2], Pattern.CASE_INSENSITIVE)));
Line 114... Line 138...
114
            return ((Number) value).intValue() == 1;
138
            return ((Number) value).intValue() == 1;
115
        }
139
        }
116
        return value != null && "1".equals(value.toString());
140
        return value != null && "1".equals(value.toString());
117
    }
141
    }
118
 
142
 
-
 
143
    /**
-
 
144
     * The label this one really means - itself, unless it is a known alias.
-
 
145
     *
-
 
146
     * Callers must run every label through this BEFORE writing anything, and must keep
-
 
147
     * using the result for the division lookup, the offer insert and the product-alias
-
 
148
     * lookup. The one place the raw label survives is offer_raw_row, which records what
-
 
149
     * the PDF actually said.
-
 
150
     */
-
 
151
    public String canonicalLabel(String label) {
-
 
152
        String target = aliases.get(label);
-
 
153
        return target == null ? label : target;
-
 
154
    }
-
 
155
 
119
    public Decision evaluate(String label, String products) {
156
    public Decision evaluate(String rawLabel, String products) {
-
 
157
        String label = canonicalLabel(rawLabel);
120
        Division division = divisions.get(label);
158
        Division division = divisions.get(label);
121
        if (division == null) {
159
        if (division == null) {
122
            return new Decision(false, "UNKNOWN division label: " + label, null, 0, null);
160
            return new Decision(false, "UNKNOWN division label: " + rawLabel, null, 0, null, label);
123
        }
161
        }
124
        if (!division.inScope) {
162
        if (!division.inScope) {
125
            return new Decision(false, "out of scope by config: " + label, null, 0, null);
163
            return new Decision(false, "out of scope by config: " + label, null, 0, null, label);
126
        }
164
        }
127
        String haystack = products == null ? "" : products;
165
        String haystack = products == null ? "" : products;
128
        List<Pattern> includeOnly = new ArrayList<>();
166
        List<Pattern> includeOnly = new ArrayList<>();
129
        // division-specific rules first, then global ones (label "")
167
        // division-specific rules first, then global ones (label "")
130
        for (String scope : new String[]{label, ""}) {
168
        for (String scope : new String[]{label, ""}) {
Line 134... Line 172...
134
            }
172
            }
135
            for (Rule rule : scoped) {
173
            for (Rule rule : scoped) {
136
                if (EXCLUDE.equals(rule.type) && rule.pattern.matcher(haystack).find()) {
174
                if (EXCLUDE.equals(rule.type) && rule.pattern.matcher(haystack).find()) {
137
                    return new Decision(false,
175
                    return new Decision(false,
138
                            "EXCLUDE rule /" + rule.pattern.pattern() + "/ on "
176
                            "EXCLUDE rule /" + rule.pattern.pattern() + "/ on "
139
                                    + (scope.isEmpty() ? "all" : scope), null, 0, null);
177
                                    + (scope.isEmpty() ? "all" : scope), null, 0, null, label);
140
                }
178
                }
141
            }
179
            }
142
            List<Pattern> includes = new ArrayList<>();
180
            List<Pattern> includes = new ArrayList<>();
143
            for (Rule rule : scoped) {
181
            for (Rule rule : scoped) {
144
                if (INCLUDE_ONLY.equals(rule.type)) {
182
                if (INCLUDE_ONLY.equals(rule.type)) {
Line 153... Line 191...
153
                        break;
191
                        break;
154
                    }
192
                    }
155
                }
193
                }
156
                if (!any) {
194
                if (!any) {
157
                    return new Decision(false, "no INCLUDE_ONLY rule matched on " + label,
195
                    return new Decision(false, "no INCLUDE_ONLY rule matched on " + label,
158
                            null, 0, null);
196
                            null, 0, null, label);
159
                }
197
                }
160
                includeOnly.addAll(includes);
198
                includeOnly.addAll(includes);
161
            }
199
            }
162
        }
200
        }
163
        String brand = brandByLabel.get(label);
201
        String brand = brandByLabel.get(label);
164
        return new Decision(true, null, brand == null ? label.split(" ")[0] : brand,
202
        return new Decision(true, null, brand == null ? label.split(" ")[0] : brand,
165
                division.categoryId, includeOnly);
203
                division.categoryId, includeOnly, label);
166
    }
204
    }
167
}
205
}