@factorypure/client-helpers 1.0.17 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +29 -2
- package/dist/index.js +271 -53
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { z } from
|
|
1
|
+
import { z } from 'zod';
|
|
2
2
|
export declare const scrapeResultsSchema: any;
|
|
3
3
|
export type ScrapeResultsType = z.infer<typeof scrapeResultsSchema>;
|
|
4
|
+
export declare const ResultIgnoreSchema: any;
|
|
5
|
+
export type ResultIgnoreType = z.infer<typeof ResultIgnoreSchema>;
|
|
4
6
|
export type ScrapeFiltersType = {
|
|
5
7
|
found_id_exclusions: number[] | null;
|
|
6
8
|
showHighPriceOutliers: boolean;
|
|
@@ -12,7 +14,8 @@ export type ScrapeFiltersType = {
|
|
|
12
14
|
skip_vendors: string[];
|
|
13
15
|
vendor_search_exclusions: string[];
|
|
14
16
|
search_exclusions: string[];
|
|
15
|
-
result_ignore_keys:
|
|
17
|
+
result_ignore_keys: ResultIgnoreType[];
|
|
18
|
+
brand_name_alternates: string[];
|
|
16
19
|
};
|
|
17
20
|
export type FilterOptionsType = {
|
|
18
21
|
exclude_linked_variants_enabled?: boolean;
|
|
@@ -39,11 +42,17 @@ export declare const HIDE_REASONS: {
|
|
|
39
42
|
CALCULATED_SKU_MISMATCH: string;
|
|
40
43
|
CRITICAL_SPEC_MISMATCH: string;
|
|
41
44
|
MANUALLY_IGNORED: string;
|
|
45
|
+
MANUALLY_EXCLUDED: string;
|
|
42
46
|
OUT_OF_STOCK_ONLINE: string;
|
|
43
47
|
REFURBISHED_USED: string;
|
|
44
48
|
SKIP_SKU: string;
|
|
45
49
|
VENDOR_EXCLUSION: string;
|
|
46
50
|
};
|
|
51
|
+
export declare const HIDE_OVERRIDE_REASONS: {
|
|
52
|
+
SKU_MATCH: string;
|
|
53
|
+
CALCULATED_SKU_MATCH: string;
|
|
54
|
+
CALCULATED_SKU_PARTIAL_MATCH: string;
|
|
55
|
+
};
|
|
47
56
|
export declare const TOO_CHEAP_MULTIPLIER = 0.75;
|
|
48
57
|
export declare const TOO_EXPENSIVE_MULTIPLIER = 1.25;
|
|
49
58
|
export declare const filterScrapeResults: ({ scrapeResults, variant, filters, filterOptions, globalScrapeOptions, }: {
|
|
@@ -63,3 +72,21 @@ export declare const calculateIgnoreStatus: (result: ScrapeResultsType, variant:
|
|
|
63
72
|
id: number;
|
|
64
73
|
sku?: string;
|
|
65
74
|
}, result_ignore_keys: string[] | null) => boolean;
|
|
75
|
+
export declare function calculateVisibility(hide_reasons: string[], hide_override_reasons: string[]): boolean;
|
|
76
|
+
export declare const calculateHideReasons: (result: ScrapeResultsType, variant: {
|
|
77
|
+
id: number;
|
|
78
|
+
title: string;
|
|
79
|
+
sku: string;
|
|
80
|
+
price: number;
|
|
81
|
+
vendor: string;
|
|
82
|
+
regexUnitResults?: any;
|
|
83
|
+
}, variantScrapeOptions: ScrapeFiltersType) => string[];
|
|
84
|
+
export declare const calculateHideOverrideReasons: (result: ScrapeResultsType, variant: {
|
|
85
|
+
id: number;
|
|
86
|
+
title: string;
|
|
87
|
+
sku: string;
|
|
88
|
+
price: number;
|
|
89
|
+
vendor: string;
|
|
90
|
+
found_product_ids?: string[];
|
|
91
|
+
}) => string[];
|
|
92
|
+
export declare function findUnitVariations(data: any): any;
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { startOfDay, subDays } from
|
|
1
|
+
import { startOfDay, subDays } from 'date-fns';
|
|
2
2
|
// @ts-ignore
|
|
3
|
-
import { Index } from
|
|
3
|
+
import { Index } from 'flexsearch';
|
|
4
4
|
// @ts-ignore
|
|
5
|
-
import EnglishPreset from
|
|
5
|
+
import EnglishPreset from 'flexsearch/lang/en';
|
|
6
6
|
// @ts-ignore
|
|
7
|
-
import { z } from
|
|
7
|
+
import { z } from 'zod';
|
|
8
8
|
export const scrapeResultsSchema = z.object({
|
|
9
9
|
id: z.number(),
|
|
10
10
|
scrape_id: z.number(),
|
|
@@ -37,21 +37,53 @@ export const scrapeResultsSchema = z.object({
|
|
|
37
37
|
store_id: z.number(),
|
|
38
38
|
match_score: z.number().nullable(),
|
|
39
39
|
});
|
|
40
|
+
export const ResultIgnoreSchema = z.object({
|
|
41
|
+
id: z.number(),
|
|
42
|
+
variant_id: z.number(),
|
|
43
|
+
title: z.string(),
|
|
44
|
+
price: z.string(),
|
|
45
|
+
source: z.string(),
|
|
46
|
+
reason: z.string(),
|
|
47
|
+
duration_days: z.number(),
|
|
48
|
+
created_by: z.number(),
|
|
49
|
+
key_parts: z.string(),
|
|
50
|
+
});
|
|
40
51
|
export const HIDE_REASONS = {
|
|
41
|
-
IGNORED:
|
|
42
|
-
HIGH_PRICE_OUTLIER:
|
|
43
|
-
LOW_PRICE_OUTLIER:
|
|
44
|
-
DATE_OUTLIER:
|
|
45
|
-
COMPETITOR_EXCLUSION:
|
|
46
|
-
DUPLICATE:
|
|
47
|
-
SEARCH_EXCLUSION:
|
|
48
|
-
CALCULATED_SKU_MISMATCH:
|
|
49
|
-
CRITICAL_SPEC_MISMATCH:
|
|
50
|
-
MANUALLY_IGNORED:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
IGNORED: 'Ignored',
|
|
53
|
+
HIGH_PRICE_OUTLIER: 'Too Expensive',
|
|
54
|
+
LOW_PRICE_OUTLIER: 'Too Cheap',
|
|
55
|
+
DATE_OUTLIER: 'Outdated Listing',
|
|
56
|
+
COMPETITOR_EXCLUSION: 'Source Excluded',
|
|
57
|
+
DUPLICATE: 'Duplicate',
|
|
58
|
+
SEARCH_EXCLUSION: 'Search Exclusion',
|
|
59
|
+
CALCULATED_SKU_MISMATCH: 'Calculated SKU Mismatch',
|
|
60
|
+
CRITICAL_SPEC_MISMATCH: 'Critical Spec Mismatch',
|
|
61
|
+
MANUALLY_IGNORED: 'Manually ignored',
|
|
62
|
+
MANUALLY_EXCLUDED: 'Manually excluded',
|
|
63
|
+
OUT_OF_STOCK_ONLINE: 'Out of stock online',
|
|
64
|
+
REFURBISHED_USED: 'Refurbished/Used',
|
|
65
|
+
SKIP_SKU: 'Skipped SKU',
|
|
66
|
+
VENDOR_EXCLUSION: 'Vendor Exclusion',
|
|
67
|
+
};
|
|
68
|
+
export const HIDE_OVERRIDE_REASONS = {
|
|
69
|
+
SKU_MATCH: 'SKU Match',
|
|
70
|
+
CALCULATED_SKU_MATCH: 'Calculated SKU Match',
|
|
71
|
+
CALCULATED_SKU_PARTIAL_MATCH: 'Calculated SKU Partial Match',
|
|
72
|
+
};
|
|
73
|
+
const HIDE_ALWAYS_MAP = {
|
|
74
|
+
[HIDE_REASONS.HIGH_PRICE_OUTLIER]: true,
|
|
75
|
+
[HIDE_REASONS.LOW_PRICE_OUTLIER]: true,
|
|
76
|
+
[HIDE_REASONS.DATE_OUTLIER]: true,
|
|
77
|
+
[HIDE_REASONS.COMPETITOR_EXCLUSION]: false,
|
|
78
|
+
[HIDE_REASONS.DUPLICATE]: true,
|
|
79
|
+
[HIDE_REASONS.SEARCH_EXCLUSION]: false,
|
|
80
|
+
[HIDE_REASONS.CALCULATED_SKU_MISMATCH]: false,
|
|
81
|
+
[HIDE_REASONS.CRITICAL_SPEC_MISMATCH]: false,
|
|
82
|
+
[HIDE_REASONS.MANUALLY_IGNORED]: true,
|
|
83
|
+
[HIDE_REASONS.OUT_OF_STOCK_ONLINE]: true,
|
|
84
|
+
[HIDE_REASONS.REFURBISHED_USED]: false,
|
|
85
|
+
[HIDE_REASONS.SKIP_SKU]: false,
|
|
86
|
+
[HIDE_REASONS.VENDOR_EXCLUSION]: false,
|
|
55
87
|
};
|
|
56
88
|
export const TOO_CHEAP_MULTIPLIER = 0.75;
|
|
57
89
|
export const TOO_EXPENSIVE_MULTIPLIER = 1.25;
|
|
@@ -105,8 +137,8 @@ const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
|
|
|
105
137
|
const tokens = [];
|
|
106
138
|
const str = content.toLowerCase();
|
|
107
139
|
// Remove symbols from the string (keep only letters, numbers, commas, and spaces)
|
|
108
|
-
const cleanedStr = str.replace(/[\/-]/g,
|
|
109
|
-
const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi,
|
|
140
|
+
const cleanedStr = str.replace(/[\/-]/g, ' ');
|
|
141
|
+
const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi, '');
|
|
110
142
|
const words = cleanedStr2.split(/\s+/);
|
|
111
143
|
for (let word of words) {
|
|
112
144
|
tokens.push(word);
|
|
@@ -117,7 +149,7 @@ const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
|
|
|
117
149
|
charset: EnglishPreset,
|
|
118
150
|
// encoder: encoder,
|
|
119
151
|
encode: customEncoder,
|
|
120
|
-
tokenize:
|
|
152
|
+
tokenize: 'strict',
|
|
121
153
|
});
|
|
122
154
|
dataToSearch.forEach((item, id) => {
|
|
123
155
|
index.add(id, item.title);
|
|
@@ -160,7 +192,7 @@ const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
|
|
|
160
192
|
nots.push(...formatted);
|
|
161
193
|
}
|
|
162
194
|
const lowerCaseTitle = title.toLowerCase();
|
|
163
|
-
const titleWithoutSku = lowerCaseTitle.replace(sku.toLowerCase(),
|
|
195
|
+
const titleWithoutSku = lowerCaseTitle.replace(sku.toLowerCase(), '');
|
|
164
196
|
const wattageTerms = Array.from(titleWithoutSku.matchAll(/\b(\d{4,5})w\b/gi)).map((match) => match[1]);
|
|
165
197
|
const wattagesToExclude = wattages.filter((wattage) => !wattageTerms.includes(wattage));
|
|
166
198
|
if (filterOptions.wattage_exclusions_enabled) {
|
|
@@ -173,15 +205,13 @@ const handleIndexSearch = (dataToSearch, filters, variant, filterOptions) => {
|
|
|
173
205
|
}
|
|
174
206
|
});
|
|
175
207
|
}
|
|
176
|
-
if (filters.search_exclusions.length &&
|
|
177
|
-
filterOptions.search_exclusions_enabled) {
|
|
208
|
+
if (filters.search_exclusions.length && filterOptions.search_exclusions_enabled) {
|
|
178
209
|
nots.push(...filters.search_exclusions);
|
|
179
210
|
}
|
|
180
|
-
if (filters.vendor_search_exclusions.length &&
|
|
181
|
-
filterOptions.skip_skus_enabled) {
|
|
211
|
+
if (filters.vendor_search_exclusions.length && filterOptions.skip_skus_enabled) {
|
|
182
212
|
nots.push(...filters.vendor_search_exclusions.filter((sku) => sku.toLowerCase() !== variant.sku.toLowerCase()));
|
|
183
213
|
}
|
|
184
|
-
if (title.toLowerCase().includes(
|
|
214
|
+
if (title.toLowerCase().includes('dual fuel')) {
|
|
185
215
|
// nots.push('tri fuel', 'trifuel', 'tri-fuel')
|
|
186
216
|
}
|
|
187
217
|
nots.forEach((term) => {
|
|
@@ -216,8 +246,8 @@ const handleVendorExclusions = (dataToSearch, filters, variant, filterOptions) =
|
|
|
216
246
|
const tokens = [];
|
|
217
247
|
const str = content.toLowerCase();
|
|
218
248
|
// Remove symbols from the string (keep only letters, numbers, commas, and spaces)
|
|
219
|
-
const cleanedStr = str.replace(/[\/-]/g,
|
|
220
|
-
const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi,
|
|
249
|
+
const cleanedStr = str.replace(/[\/-]/g, ' ');
|
|
250
|
+
const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi, '');
|
|
221
251
|
const words = cleanedStr2.split(/\s+/);
|
|
222
252
|
for (let word of words) {
|
|
223
253
|
tokens.push(word);
|
|
@@ -228,7 +258,7 @@ const handleVendorExclusions = (dataToSearch, filters, variant, filterOptions) =
|
|
|
228
258
|
charset: EnglishPreset,
|
|
229
259
|
// encoder: encoder,
|
|
230
260
|
encode: customEncoder,
|
|
231
|
-
tokenize:
|
|
261
|
+
tokenize: 'strict',
|
|
232
262
|
});
|
|
233
263
|
dataToSearch.forEach((item, id) => {
|
|
234
264
|
index.add(id, item.title);
|
|
@@ -299,8 +329,8 @@ const handleSkipSkuSearch = (dataToSearch, filters, variant, filterOptions) => {
|
|
|
299
329
|
const tokens = [];
|
|
300
330
|
const str = content.toLowerCase();
|
|
301
331
|
// Remove symbols from the string (keep only letters, numbers, commas, and spaces)
|
|
302
|
-
const cleanedStr = str.replace(/[\/-]/g,
|
|
303
|
-
const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi,
|
|
332
|
+
const cleanedStr = str.replace(/[\/-]/g, ' ');
|
|
333
|
+
const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi, '');
|
|
304
334
|
const words = cleanedStr2.split(/\s+/);
|
|
305
335
|
for (let word of words) {
|
|
306
336
|
tokens.push(word);
|
|
@@ -311,7 +341,7 @@ const handleSkipSkuSearch = (dataToSearch, filters, variant, filterOptions) => {
|
|
|
311
341
|
charset: EnglishPreset,
|
|
312
342
|
// encoder: encoder,
|
|
313
343
|
encode: customEncoder,
|
|
314
|
-
tokenize:
|
|
344
|
+
tokenize: 'strict',
|
|
315
345
|
});
|
|
316
346
|
dataToSearch.forEach((item, id) => {
|
|
317
347
|
index.add(id, item.title);
|
|
@@ -378,8 +408,8 @@ const handleExclusionsSearch = (dataToSearch, filters, variant, filterOptions) =
|
|
|
378
408
|
const tokens = [];
|
|
379
409
|
const str = content.toLowerCase();
|
|
380
410
|
// Remove symbols from the string (keep only letters, numbers, commas, and spaces)
|
|
381
|
-
const cleanedStr = str.replace(/[\/-]/g,
|
|
382
|
-
const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi,
|
|
411
|
+
const cleanedStr = str.replace(/[\/-]/g, ' ');
|
|
412
|
+
const cleanedStr2 = cleanedStr.replace(/[^a-z0-9,\/\s]/gi, '');
|
|
383
413
|
const words = cleanedStr2.split(/\s+/);
|
|
384
414
|
for (let word of words) {
|
|
385
415
|
tokens.push(word);
|
|
@@ -390,7 +420,7 @@ const handleExclusionsSearch = (dataToSearch, filters, variant, filterOptions) =
|
|
|
390
420
|
charset: EnglishPreset,
|
|
391
421
|
// encoder: encoder,
|
|
392
422
|
encode: customEncoder,
|
|
393
|
-
tokenize:
|
|
423
|
+
tokenize: 'strict',
|
|
394
424
|
});
|
|
395
425
|
dataToSearch.forEach((item, id) => {
|
|
396
426
|
index.add(id, item.title);
|
|
@@ -456,8 +486,7 @@ const filterLinkedElsewhereResults = (results, variantId) => {
|
|
|
456
486
|
parsedLinkedVariantIds = [];
|
|
457
487
|
}
|
|
458
488
|
}
|
|
459
|
-
const productLinkedElsewhere = parsedLinkedVariantIds.length > 0 &&
|
|
460
|
-
!parsedLinkedVariantIds.includes(variantId);
|
|
489
|
+
const productLinkedElsewhere = parsedLinkedVariantIds.length > 0 && !parsedLinkedVariantIds.includes(variantId);
|
|
461
490
|
if (productLinkedElsewhere) {
|
|
462
491
|
return false;
|
|
463
492
|
}
|
|
@@ -596,37 +625,226 @@ export const calculateIgnoreStatus = (result, variant, result_ignore_keys) => {
|
|
|
596
625
|
if (result_ignore_keys && result_ignore_keys.includes(resultKey)) {
|
|
597
626
|
ignore = true;
|
|
598
627
|
}
|
|
599
|
-
if (result.details_and_offers &&
|
|
600
|
-
result.details_and_offers.includes("Out of stock online")) {
|
|
628
|
+
if (result.details_and_offers && result.details_and_offers.includes('Out of stock online')) {
|
|
601
629
|
ignore = true;
|
|
602
630
|
}
|
|
603
631
|
const refurbishedKeywords = [
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
632
|
+
'refurbished',
|
|
633
|
+
'renewed',
|
|
634
|
+
'reconditioned',
|
|
635
|
+
'refurb',
|
|
636
|
+
'remanufactured',
|
|
637
|
+
'scratch',
|
|
638
|
+
'dent',
|
|
639
|
+
'used',
|
|
612
640
|
`${variant.sku}-R`,
|
|
613
641
|
`${variant.sku}-R`.toLowerCase(),
|
|
614
642
|
`${variant.sku}-R`.toUpperCase(),
|
|
615
643
|
`${variant.sku?.toLowerCase()}-R`,
|
|
616
644
|
`${variant.sku?.toUpperCase()}-R`,
|
|
617
645
|
];
|
|
618
|
-
const normalizedTitle = result.title
|
|
619
|
-
.toLowerCase()
|
|
620
|
-
.replace(/[^a-z0-9-]/g, " ");
|
|
646
|
+
const normalizedTitle = result.title.toLowerCase().replace(/[^a-z0-9-]/g, ' ');
|
|
621
647
|
const isRefurbished = refurbishedKeywords.some((keyword) => normalizedTitle.split(/\s+/).includes(keyword)) ||
|
|
622
|
-
(result.details_and_offers &&
|
|
623
|
-
result.details_and_offers.includes("Pre-owned"));
|
|
648
|
+
(result.details_and_offers && result.details_and_offers.includes('Pre-owned'));
|
|
624
649
|
if (isRefurbished) {
|
|
625
650
|
ignore = true;
|
|
626
651
|
}
|
|
627
652
|
return ignore;
|
|
628
653
|
};
|
|
654
|
+
export function calculateVisibility(hide_reasons, hide_override_reasons) {
|
|
655
|
+
if (!hide_reasons || hide_reasons.length === 0) {
|
|
656
|
+
// no reason to hide
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
if (hide_reasons.some((reason) => HIDE_ALWAYS_MAP[reason])) {
|
|
660
|
+
// has a reason that should always hide
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
if (!hide_override_reasons || hide_override_reasons.length === 0) {
|
|
664
|
+
// has reasons to hide, no overrides
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
// has reasons to hide, has overrides
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
629
670
|
function getUndercutThreshold(price, undercutThresholdRanges) {
|
|
630
671
|
const range = undercutThresholdRanges.find((r) => price >= r.min && price <= r.max);
|
|
631
672
|
return range ? range.threshold : 0.75; // fallback default
|
|
632
673
|
}
|
|
674
|
+
export const calculateHideReasons = (result, variant, variantScrapeOptions) => {
|
|
675
|
+
const hide_reasons = [];
|
|
676
|
+
if (variantScrapeOptions.result_ignore_keys && variantScrapeOptions.result_ignore_keys.length > 0) {
|
|
677
|
+
variantScrapeOptions.result_ignore_keys.forEach((key) => {
|
|
678
|
+
const resultKeyValues = [variant.id];
|
|
679
|
+
const keyValues = [];
|
|
680
|
+
const keyParts = JSON.parse(key.key_parts);
|
|
681
|
+
keyParts.forEach((part) => {
|
|
682
|
+
keyValues.push(key[part]);
|
|
683
|
+
if (part !== 'variant_id') {
|
|
684
|
+
resultKeyValues.push(result[part === 'price' ? 'extracted_price' : part]);
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
const parsedIgnoreKey = keyValues.join('-');
|
|
688
|
+
const resultIgnoreKey = resultKeyValues.join('-');
|
|
689
|
+
if (parsedIgnoreKey === resultIgnoreKey) {
|
|
690
|
+
key.reason === 'Ignored'
|
|
691
|
+
? hide_reasons.push('Manually ignored')
|
|
692
|
+
: hide_reasons.push('Manually excluded');
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
if (result.brand) {
|
|
697
|
+
const vendor = variant.vendor ? variant.vendor.toLowerCase() : null;
|
|
698
|
+
const brandNameAlternates = variantScrapeOptions.brand_name_alternates;
|
|
699
|
+
const targetBrands = [vendor, ...(brandNameAlternates || [])].filter((b) => b).map((b) => b?.toLowerCase());
|
|
700
|
+
const calcBrandMatched = result.brand && result.brand !== '' ? targetBrands.includes(result.brand.toLowerCase()) : null;
|
|
701
|
+
if (calcBrandMatched === false) {
|
|
702
|
+
hide_reasons.push('Calculated Brand Mismatch');
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
if (result.details_and_offers && result.details_and_offers.includes('Out of stock online')) {
|
|
706
|
+
hide_reasons.push('Out of stock online');
|
|
707
|
+
}
|
|
708
|
+
if (result.calculated_sku && result.calculated_sku?.toLowerCase() !== variant.sku.toLowerCase()) {
|
|
709
|
+
hide_reasons.push('Calculated SKU Mismatch');
|
|
710
|
+
}
|
|
711
|
+
if (result.regexUnitResults && variant.regexUnitResults) {
|
|
712
|
+
const [regexIgnore, regexIgnoreReasons] = getRegexUnitResultsIgnore(result.regexUnitResults, variant.regexUnitResults, result, variant);
|
|
713
|
+
if (regexIgnore) {
|
|
714
|
+
hide_reasons.push(...regexIgnoreReasons);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
const refurbishedKeywords = [
|
|
718
|
+
'refurbished',
|
|
719
|
+
'renewed',
|
|
720
|
+
'reconditioned',
|
|
721
|
+
'refurb',
|
|
722
|
+
'remanufactured',
|
|
723
|
+
'scratch',
|
|
724
|
+
'dent',
|
|
725
|
+
'used',
|
|
726
|
+
`${variant.sku}-R`,
|
|
727
|
+
`${variant.sku}-R`.toLowerCase(),
|
|
728
|
+
`${variant.sku}-R`.toUpperCase(),
|
|
729
|
+
`${variant.sku?.toLowerCase()}-R`,
|
|
730
|
+
`${variant.sku?.toUpperCase()}-R`,
|
|
731
|
+
];
|
|
732
|
+
const normalizedTitle = result.title.toLowerCase().replace(/[^a-z0-9-]/g, ' ');
|
|
733
|
+
const isRefurbished = refurbishedKeywords.some((keyword) => normalizedTitle.split(/\s+/).includes(keyword)) ||
|
|
734
|
+
(result.details_and_offers && result.details_and_offers.includes('Pre-owned'));
|
|
735
|
+
if (isRefurbished) {
|
|
736
|
+
hide_reasons.push('Refurbished/Used');
|
|
737
|
+
}
|
|
738
|
+
return hide_reasons;
|
|
739
|
+
};
|
|
740
|
+
export const calculateHideOverrideReasons = (result, variant) => {
|
|
741
|
+
const hide_override_reasons = [];
|
|
742
|
+
const skuRegex = new RegExp(`\\b${variant.sku}\\b`, 'gi');
|
|
743
|
+
if (skuRegex.test(result.title)) {
|
|
744
|
+
hide_override_reasons.push('SKU Match');
|
|
745
|
+
}
|
|
746
|
+
if (variant.sku.toLowerCase() === result.calculated_sku?.toLowerCase()) {
|
|
747
|
+
hide_override_reasons.push('Calculated SKU Match');
|
|
748
|
+
}
|
|
749
|
+
if (variant.found_product_ids && variant.found_product_ids.includes(result.found_product_id)) {
|
|
750
|
+
hide_override_reasons.push('Product Id Linked');
|
|
751
|
+
}
|
|
752
|
+
return hide_override_reasons;
|
|
753
|
+
};
|
|
754
|
+
function getRegexUnitResultsIgnore(resultRegexResults, variantRegexResults, result, variant) {
|
|
755
|
+
const failedUnits = [];
|
|
756
|
+
for (const unit in variantRegexResults) {
|
|
757
|
+
const variations = variantRegexResults[unit];
|
|
758
|
+
if (variations.length === 0)
|
|
759
|
+
continue;
|
|
760
|
+
const mostCommonVariation = variations[0];
|
|
761
|
+
const targetVariations = resultRegexResults[unit] || [];
|
|
762
|
+
if (targetVariations.length === 0)
|
|
763
|
+
continue;
|
|
764
|
+
const matchingVariation = resultRegexResults[unit].find((v) => v.normalized === mostCommonVariation.normalized);
|
|
765
|
+
if (!matchingVariation) {
|
|
766
|
+
// A unit exists in both the target and variant, but no matching variations were found
|
|
767
|
+
failedUnits.push(unit);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
const criticalUnits = ['ton', 'cc', 'hp'];
|
|
771
|
+
const ignoreReasons = [];
|
|
772
|
+
for (const criticalUnit of criticalUnits) {
|
|
773
|
+
if (failedUnits.includes(criticalUnit)) {
|
|
774
|
+
ignoreReasons.push(`Critical Spec Mismatch`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
if (ignoreReasons.length === 0) {
|
|
778
|
+
return [false, []];
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
return [true, ignoreReasons];
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
export function findUnitVariations(data) {
|
|
785
|
+
const units = ['inch', 'cm', 'hp', 'cc', 'ton', 'lbs', 'volts', 'amp', 'ah', 'watt', 'mph', 'mile'];
|
|
786
|
+
const results = {
|
|
787
|
+
inch: [],
|
|
788
|
+
cm: [],
|
|
789
|
+
hp: [],
|
|
790
|
+
cc: [],
|
|
791
|
+
ton: [],
|
|
792
|
+
lbs: [],
|
|
793
|
+
volts: [],
|
|
794
|
+
amp: [],
|
|
795
|
+
watt: [],
|
|
796
|
+
mph: [],
|
|
797
|
+
mile: [],
|
|
798
|
+
ah: [],
|
|
799
|
+
};
|
|
800
|
+
units.forEach((unit) => {
|
|
801
|
+
const escapedUnit = unit.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
802
|
+
let variationsRegex;
|
|
803
|
+
if (unit === '"' || unit.toLowerCase() === 'inch') {
|
|
804
|
+
// Match numbers (integer or decimal) followed by ", ”, in, inch, inches, -in, - inch, etc.
|
|
805
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(?:(\\"|\\u201d)|("|”)|in(ch(es)?)?|-\s*in(ch(es)?)?)/gi;
|
|
806
|
+
}
|
|
807
|
+
else if (unit.toLowerCase() === 'cm') {
|
|
808
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(cm|centimeter(s)?)/gi;
|
|
809
|
+
}
|
|
810
|
+
else if (unit.toLowerCase() === 'volts') {
|
|
811
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(v|volts|volt)/gi;
|
|
812
|
+
}
|
|
813
|
+
else if (unit.toLowerCase() === 'lbs') {
|
|
814
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(lb|lbs|pounds|pound)/gi;
|
|
815
|
+
}
|
|
816
|
+
else if (unit.toLowerCase() === 'hp') {
|
|
817
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(hp|horsepower|horse power)/gi;
|
|
818
|
+
}
|
|
819
|
+
else if (unit.toLowerCase() === 'mph') {
|
|
820
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(mph|miles per hour|mile per hour)/gi;
|
|
821
|
+
}
|
|
822
|
+
else if (unit.toLowerCase() === 'amp') {
|
|
823
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(?<!A?W?G\s*)(A\b|amp\b|amps\b|amperes\b|ampere\b)/gi;
|
|
824
|
+
}
|
|
825
|
+
else if (unit.toLowerCase() === 'ah') {
|
|
826
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(ah|ampere hours|amp hour|amp hours)/gi;
|
|
827
|
+
}
|
|
828
|
+
else if (unit.toLowerCase() === 'cc') {
|
|
829
|
+
variationsRegex = /\b\d+(\.\d+)?-?\s*(cc|cubic centimeters|cubic centimeter)/gi;
|
|
830
|
+
}
|
|
831
|
+
else if (unit.toLowerCase() === 'ton') {
|
|
832
|
+
variationsRegex = /\b\d+(\.\d+)?\s*-?\s*(ton|tons)/gi;
|
|
833
|
+
}
|
|
834
|
+
else {
|
|
835
|
+
// Generic: number + unit, with optional dash or space
|
|
836
|
+
variationsRegex = new RegExp(`\\b\\d+(\\.\\d+)?\\s*(-?\\s*${escapedUnit})`, 'gi');
|
|
837
|
+
}
|
|
838
|
+
const matches = [];
|
|
839
|
+
const sampleText = JSON.stringify(data);
|
|
840
|
+
let match;
|
|
841
|
+
while ((match = variationsRegex.exec(sampleText)) !== null) {
|
|
842
|
+
matches.push({ value: match[0], source: match[0], normalized: match[0].replace(/[^\d.]/g, '') });
|
|
843
|
+
}
|
|
844
|
+
results[unit] = matches;
|
|
845
|
+
if (results[unit].length === 0) {
|
|
846
|
+
delete results[unit];
|
|
847
|
+
}
|
|
848
|
+
});
|
|
849
|
+
return results;
|
|
850
|
+
}
|