@factorypure/client-helpers 1.0.17 → 1.0.18

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 CHANGED
@@ -1,6 +1,8 @@
1
- import { z } from "zod";
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,7 @@ export type ScrapeFiltersType = {
12
14
  skip_vendors: string[];
13
15
  vendor_search_exclusions: string[];
14
16
  search_exclusions: string[];
15
- result_ignore_keys: string[] | null;
17
+ result_ignore_keys: ResultIgnoreType[];
16
18
  };
17
19
  export type FilterOptionsType = {
18
20
  exclude_linked_variants_enabled?: boolean;
@@ -39,11 +41,17 @@ export declare const HIDE_REASONS: {
39
41
  CALCULATED_SKU_MISMATCH: string;
40
42
  CRITICAL_SPEC_MISMATCH: string;
41
43
  MANUALLY_IGNORED: string;
44
+ MANUALLY_EXCLUDED: string;
42
45
  OUT_OF_STOCK_ONLINE: string;
43
46
  REFURBISHED_USED: string;
44
47
  SKIP_SKU: string;
45
48
  VENDOR_EXCLUSION: string;
46
49
  };
50
+ export declare const HIDE_OVERRIDE_REASONS: {
51
+ SKU_MATCH: string;
52
+ CALCULATED_SKU_MATCH: string;
53
+ CALCULATED_SKU_PARTIAL_MATCH: string;
54
+ };
47
55
  export declare const TOO_CHEAP_MULTIPLIER = 0.75;
48
56
  export declare const TOO_EXPENSIVE_MULTIPLIER = 1.25;
49
57
  export declare const filterScrapeResults: ({ scrapeResults, variant, filters, filterOptions, globalScrapeOptions, }: {
@@ -63,3 +71,4 @@ export declare const calculateIgnoreStatus: (result: ScrapeResultsType, variant:
63
71
  id: number;
64
72
  sku?: string;
65
73
  }, result_ignore_keys: string[] | null) => boolean;
74
+ export declare function calculateVisibility(hide_reasons: string[], hide_override_reasons: string[]): boolean;
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { startOfDay, subDays } from "date-fns";
1
+ import { startOfDay, subDays } from 'date-fns';
2
2
  // @ts-ignore
3
- import { Index } from "flexsearch";
3
+ import { Index } from 'flexsearch';
4
4
  // @ts-ignore
5
- import EnglishPreset from "flexsearch/lang/en";
5
+ import EnglishPreset from 'flexsearch/lang/en';
6
6
  // @ts-ignore
7
- import { z } from "zod";
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: "Ignored",
42
- HIGH_PRICE_OUTLIER: "Too Expensive",
43
- LOW_PRICE_OUTLIER: "Too Cheap",
44
- DATE_OUTLIER: "Outdated Listing",
45
- COMPETITOR_EXCLUSION: "Source Excluded",
46
- DUPLICATE: "Duplicate",
47
- SEARCH_EXCLUSION: "Search Exclusion",
48
- CALCULATED_SKU_MISMATCH: "Calculated SKU Mismatch",
49
- CRITICAL_SPEC_MISMATCH: "Critical Spec Mismatch",
50
- MANUALLY_IGNORED: "Manually ignored",
51
- OUT_OF_STOCK_ONLINE: "Out of stock online",
52
- REFURBISHED_USED: "Refurbished/Used",
53
- SKIP_SKU: "Skipped SKU",
54
- VENDOR_EXCLUSION: "Vendor Exclusion",
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: "strict",
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("dual fuel")) {
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: "strict",
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: "strict",
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: "strict",
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,36 +625,48 @@ 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
- "refurbished",
605
- "renewed",
606
- "reconditioned",
607
- "refurb",
608
- "remanufactured",
609
- "scratch",
610
- "dent",
611
- "used",
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@factorypure/client-helpers",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",