@bytebrand/export-cars 1.24.1 → 1.26.0

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.
Files changed (31) hide show
  1. package/dist/constants/fb.constants.d.ts +5 -3
  2. package/dist/constants/fb.constants.js +6 -4
  3. package/dist/constants/fb.constants.js.map +1 -1
  4. package/dist/exporters/facebook-shop.exporter.js +6 -4
  5. package/dist/exporters/facebook-shop.exporter.js.map +1 -1
  6. package/dist/formats/facebook-shop.builder.d.ts +3 -3
  7. package/dist/formats/facebook-shop.builder.js +21 -15
  8. package/dist/formats/facebook-shop.builder.js.map +1 -1
  9. package/dist/formats/fb-xml.builder.js +2 -2
  10. package/dist/formats/fb-xml.builder.js.map +1 -1
  11. package/dist/interfaces/export-item.interface.d.ts +21 -35
  12. package/dist/services/rules.service.d.ts +1 -1
  13. package/dist/transformers/facebook-shop.transformer.d.ts +1 -2
  14. package/dist/transformers/facebook-shop.transformer.js +22 -42
  15. package/dist/transformers/facebook-shop.transformer.js.map +1 -1
  16. package/dist/transformers/fb.transformer.js +6 -7
  17. package/dist/transformers/fb.transformer.js.map +1 -1
  18. package/dist/transformers/google.transformer.d.ts +4 -2
  19. package/dist/transformers/google.transformer.js +15 -2
  20. package/dist/transformers/google.transformer.js.map +1 -1
  21. package/dist/tsconfig.build.tsbuildinfo +1 -1
  22. package/dist/tsconfig.tsbuildinfo +1 -0
  23. package/package.json +1 -1
  24. package/src/constants/fb.constants.ts +8 -3
  25. package/src/exporters/facebook-shop.exporter.ts +6 -4
  26. package/src/formats/facebook-shop.builder.ts +59 -46
  27. package/src/formats/fb-xml.builder.ts +2 -2
  28. package/src/interfaces/export-item.interface.ts +25 -37
  29. package/src/transformers/facebook-shop.transformer.ts +26 -45
  30. package/src/transformers/fb.transformer.ts +6 -7
  31. package/src/transformers/google.transformer.ts +18 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebrand/export-cars",
3
- "version": "1.24.1",
3
+ "version": "1.26.0",
4
4
  "description": "",
5
5
  "author": "bytebrand",
6
6
  "license": "UNLICENSED",
@@ -8,12 +8,17 @@ export const TIMESTAMP_FIRST_YEAR = 1970;
8
8
  export const META_PUSH_PRIORITY_STANDARD = 'standard';
9
9
  export const META_PUSH_PRIORITY_ALLOWED_VALUES = ['dealer_priority_1', 'dealer_priority_2'];
10
10
 
11
+ // Values must match Meta's Automotive Model Ads offer_type enum exactly (lease/finance/cash) —
12
+ // the old 'financing'/'leasing'/'buy' values are not recognized by the AMA Vehicle Offers Feed.
11
13
  export enum OfferType {
12
- financing = 'financing',
13
- leasing = 'leasing',
14
- buy = 'buy',
14
+ financing = 'finance',
15
+ leasing = 'lease',
16
+ buy = 'cash',
15
17
  }
16
18
 
19
+ export const AMOUNT_QUALIFIER_APR = 'APR';
20
+ export const TERM_QUALIFIER_MONTHS = 'months';
21
+
17
22
  export const OFFER_DISCLAIMER = 'Für Ihre Finanzierungswünsche stellen wir eine Bonitätsanfrage. Bonität ' +
18
23
  'vorausgesetzt, ist dies ein repräsentatives Berechnungsbeispiel gem. der Angaben, welches 2/3 aller Kunden, ' +
19
24
  'im Sinne des § 17a Abs. 4 PAngV, erhalten. Dieses freibleibende Angebot der Santander Consumer Bank AG, ' +
@@ -1,5 +1,6 @@
1
1
  import { Injectable } from '@nestjs/common';
2
2
  import { ModuleRef } from '@nestjs/core';
3
+ import { basename } from 'path';
3
4
 
4
5
  import { CronicleUtils } from '@bytebrand/cronicle-helper';
5
6
  import { FsChunkInterface } from '@bytebrand/chunkable';
@@ -24,8 +25,9 @@ export class FacebookShopExporter implements Exporter {
24
25
  await CronicleUtils.ensureDir(this.configService.config.pathesConfig.localConvertedDirectory);
25
26
  await CronicleUtils.emptyDir(this.configService.config.pathesConfig.localConvertedDirectory);
26
27
 
27
- const facebookShopXmkBuilder = new FacebookShopXmlBuilder(fileXml);
28
- await facebookShopXmkBuilder.buildStart();
28
+ const selfUrl = `https://ftp.${this.configService.config.domain}/feeds/${basename(fileXml)}`;
29
+ const facebookShopXmlBuilder = new FacebookShopXmlBuilder(fileXml);
30
+ await facebookShopXmlBuilder.buildStart(selfUrl);
29
31
 
30
32
  const facebookShopTransformer = await this.moduleRef.create(FacebookShopTransformer);
31
33
 
@@ -45,13 +47,13 @@ export class FacebookShopExporter implements Exporter {
45
47
  }
46
48
 
47
49
  for (const item of items) {
48
- await facebookShopXmkBuilder.addItem(item);
50
+ await facebookShopXmlBuilder.addItem(item);
49
51
  }
50
52
  this.carService.counter.countCar(data.images);
51
53
  }
52
54
  });
53
55
 
54
- await facebookShopXmkBuilder.buildEnd();
56
+ await facebookShopXmlBuilder.buildEnd();
55
57
 
56
58
  console.log(this.carService.counter.getCountedCars());
57
59
  }
@@ -1,46 +1,59 @@
1
- import { escape, isNumber, isString } from 'lodash';
2
- import { XMLBuilderBase } from '@bytebrand/cronicle-helper';
3
- import { FacebookShopItem, FacebookShopTag } from '../interfaces';
4
-
5
- export class FacebookShopXmlBuilder extends XMLBuilderBase {
6
- async buildStart(): Promise<void> {
7
- await this.write(
8
- '<?xml version="1.0" encoding="utf-8"?>\n<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0" xmlns:atom="http://www.w3.org/2005/Atom">' +
9
- '\n<channel>\n<title>Produkt für auto.de</title>\n<description>Produkt für auto.de</description> \n<link>https://www.auto.de/</link>\n' +
10
- '<atom:link href="https://www.mydealsshop.foo/pages/test-feed" rel="self" type="application/rss+xml" />\n',
11
- );
12
- }
13
-
14
- async addItem(car: FacebookShopItem): Promise<void> {
15
- let item = '\n<item>\n';
16
-
17
- const tags = Object.keys(car);
18
-
19
- for (const tag of tags) {
20
- item += this.buildTagElement(tag, car[tag]);
21
- }
22
- item += '</item>';
23
-
24
- await this.write(item);
25
- }
26
-
27
- buildTagElement(tag: string, params: FacebookShopTag) {
28
- // getElement() treats falsy values as "missing" — stringify numbers first so a
29
- // legitimate 0 (e.g. down_payment/apr) still renders instead of an empty tag.
30
- let value = params.value;
31
- if (isString(value)) {
32
- value = escape(value);
33
- } else if (isNumber(value)) {
34
- value = String(value);
35
- }
36
- if (params.isGoogle) {
37
- return this.getElement(`g:${tag}`, value);
38
- }
39
- return this.getElement(tag, value);
40
- }
41
-
42
- async buildEnd(): Promise<void> {
43
- await this.write('\n</channel>\n</rss>\n');
44
- await this.end();
45
- }
46
- }
1
+ import { escape, isNil, isNumber, isString } from 'lodash';
2
+ import { XMLBuilderBase } from '@bytebrand/cronicle-helper';
3
+ import { FacebookShopItem } from '../interfaces';
4
+
5
+ const MAX_IMAGES = 2;
6
+
7
+ export class FacebookShopXmlBuilder extends XMLBuilderBase {
8
+ // No xmlns:g / g: prefixes here — that namespace belongs to the old Google Merchant /
9
+ // Facebook Shop product-catalog schema. Meta's Automotive Model Ads Vehicle Offers Feed
10
+ // uses plain, undecorated tag names (see facebook-shop.builder field reference above).
11
+ async buildStart(selfUrl?: string): Promise<void> {
12
+ await this.write(
13
+ '<?xml version="1.0" encoding="utf-8"?>\n<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">' +
14
+ '\n<channel>\n<title>auto.de Vehicle Offers Feed</title>' +
15
+ '\n<description>Automotive Model Ads Vehicle Offers Feed für auto.de</description>' +
16
+ '\n<link>https://www.auto.de/</link>' +
17
+ `\n<atom:link href="${escape(selfUrl)}" rel="self" type="application/rss+xml" />\n`,
18
+ );
19
+ }
20
+
21
+ async addItem(car: FacebookShopItem): Promise<void> {
22
+ let item = '\n<item>\n';
23
+
24
+ const { image, ...tags } = car;
25
+
26
+ for (const [tag, value] of Object.entries(tags)) {
27
+ item += this.buildTagElement(tag, value);
28
+ }
29
+
30
+ item += image
31
+ .slice(0, MAX_IMAGES)
32
+ .map((url: string) => `<image><url>${escape(url)}</url></image>\n`)
33
+ .join('');
34
+
35
+ item += '</item>';
36
+
37
+ await this.write(item);
38
+ }
39
+
40
+ private buildTagElement(tag: string, value: unknown): string {
41
+ if (isNil(value) || value === '') {
42
+ return '';
43
+ }
44
+ // getElement() treats falsy values as "missing" — stringify numbers first so a
45
+ // legitimate 0 (e.g. downpayment/term_length) still renders instead of an empty tag.
46
+ if (isString(value)) {
47
+ return this.getElement(tag, escape(value));
48
+ }
49
+ if (isNumber(value)) {
50
+ return this.getElement(tag, String(value));
51
+ }
52
+ return this.getElement(tag, value);
53
+ }
54
+
55
+ async buildEnd(): Promise<void> {
56
+ await this.write('\n</channel>\n</rss>\n');
57
+ await this.end();
58
+ }
59
+ }
@@ -16,8 +16,8 @@ export class FbXmlBuilder extends XMLBuilderBase {
16
16
  if (key === 'description') {
17
17
  return this.getDescriptionElement(key, data);
18
18
  }
19
- if (key === 'additional_image_link' && Array.isArray(data)) {
20
- return data.map((value: string) => this.getElement(key, value, true)).join('');
19
+ if (key === 'image' && Array.isArray(data)) {
20
+ return this.getElementsArray(key, data.map((url: string) => ({ url })));
21
21
  }
22
22
  if (key === 'vehicle_specifications' && Array.isArray(data)) {
23
23
  // getElement() treats falsy values as "missing" — stringify so a legitimate 0
@@ -207,6 +207,7 @@ export interface GoogleXmlItem {
207
207
  identifier_exists: string,
208
208
  ads_redirect?: string;
209
209
  "certified_pre-owned"?: boolean;
210
+ user_id?: string;
210
211
  custom_label_0?: string;
211
212
  custom_label_1?: string,
212
213
  custom_label_2?: string,
@@ -345,46 +346,33 @@ export interface dealerItem {
345
346
  };
346
347
  }
347
348
 
349
+ // Field set matches Meta's Automotive Model Ads "Vehicle Offers Feed File" reference
350
+ // (https://developers.facebook.com/documentation/ads-commerce/marketing-api/auto-ads/reference#vehicle-offers-feed-file).
351
+ // custom_label_4 is not part of that reference but is kept per ADV-159/161 (dealer push
352
+ // priority) — Meta ignores catalog fields it doesn't recognize rather than rejecting the feed.
348
353
  export interface FacebookShopItem {
349
- id: FacebookShopTag;
350
- vehicle_id: FacebookShopTag;
351
- title: FacebookShopTag;
352
- description: FacebookShopTag;
353
- availability: FacebookShopTag;
354
- condition: FacebookShopTag;
355
- price: FacebookShopTag;
356
- link: FacebookShopTag;
357
- image_link: FacebookShopTag;
358
- additional_image_link: FacebookShopTag;
359
- make: FacebookShopTag;
360
- model: FacebookShopTag;
361
- year: FacebookShopTag;
362
-
363
- user_id: FacebookShopTag;
364
- custom_label_4: FacebookShopTag;
365
- dealer_privacy_policy_url: FacebookShopTag;
366
-
367
- offer_type: FacebookShopTag;
368
- offer_disclaimer?: FacebookShopTag;
369
- monthly_payment?: FacebookShopTag;
370
- down_payment?: FacebookShopTag;
371
- term_length?: FacebookShopTag;
372
- apr?: FacebookShopTag;
373
- final_payment?: FacebookShopTag;
374
- total_amount?: FacebookShopTag;
375
- net_loan_amount?: FacebookShopTag;
354
+ vehicle_offer_id: string;
355
+ make: string;
356
+ model: string;
357
+ year: string;
358
+ offer_type: string;
359
+ title: string;
360
+ offer_description: string;
361
+ url: string;
362
+ offer_disclaimer?: string;
363
+ image: string[];
376
364
 
377
- quantity_to_sell_on_facebook: FacebookShopTag;
378
- google_product_category: FacebookShopTag;
379
- sale_price: FacebookShopTag;
380
- status: FacebookShopTag;
381
- color: FacebookShopTag;
382
- product_type: FacebookShopTag;
383
- }
365
+ price: string;
366
+ availability: string;
367
+ exterior_color: string;
368
+ custom_label_4: string;
384
369
 
385
- export interface FacebookShopTag {
386
- isGoogle: boolean;
387
- value: any;
370
+ amount_price?: string;
371
+ amount_percentage?: string;
372
+ amount_qualifier?: string;
373
+ term_length?: number;
374
+ term_qualifier?: string;
375
+ downpayment?: string;
388
376
  }
389
377
 
390
378
  export interface TrovitXmlItem {
@@ -9,13 +9,15 @@ import { TranslatorExtended } from '@bytebrand/schema-tools';
9
9
  import { DataSchemes } from '@bytebrand/car-schema';
10
10
  import { getComputedFinancing, normalizeRateObject } from '@bytebrand/fe-financing';
11
11
 
12
- import { FacebookShopItem, FacebookShopTag } from '../interfaces';
12
+ import { FacebookShopItem } from '../interfaces';
13
13
  import { ConfigService, ImagesService, MappingService } from '../services';
14
14
  import {
15
+ AMOUNT_QUALIFIER_APR,
15
16
  META_PUSH_PRIORITY_ALLOWED_VALUES,
16
17
  META_PUSH_PRIORITY_STANDARD,
17
18
  OFFER_DISCLAIMER,
18
19
  OfferType,
20
+ TERM_QUALIFIER_MONTHS,
19
21
  } from '../constants/fb.constants';
20
22
 
21
23
  interface OfferFinancials {
@@ -77,36 +79,26 @@ export class FacebookShopTransformer {
77
79
  }
78
80
 
79
81
  const base = {
80
- vehicle_id: this.tag(vehicleId, true),
81
- availability: this.tag('in stock', true),
82
- condition: this.tag(this.getCondition(car), true),
83
- price: this.tag(`${price} EUR`, true),
84
- sale_price: this.tag(`${price} EUR`, true),
85
- link: this.tag(this.getCarLink(car), true),
86
- image_link: this.tag(imageLinks[0], true),
87
- additional_image_link: this.tag(imageLinks[0], false),
88
- make: this.tag(make, false),
89
- model: this.tag(model, false),
90
- year: this.tag(this.getYear(car), false),
91
- user_id: this.tag(ownerId, false),
92
- custom_label_4: this.tag(customLabel4, false),
93
- dealer_privacy_policy_url: this.tag('https://www.auto.de/einwilligungserklaerung/', false),
94
- quantity_to_sell_on_facebook: this.tag(1, true),
95
- google_product_category: this.tag('916', true),
96
- status: this.tag('active', true),
97
- color: this.tag(this.getColor(car), false),
98
- product_type: this.tag('Vehicles & Parts > Vehicles > Motor Vehicles > Cars, Trucks & Vans', true),
82
+ make,
83
+ model,
84
+ year: this.getYear(car),
85
+ url: this.getCarLink(car),
86
+ image: imageLinks.slice(0, 2), // main + 2nd image, per ticket
87
+ price: `${price} EUR`,
88
+ availability: this.getAvailability(car),
89
+ exterior_color: this.getColor(car),
90
+ custom_label_4: customLabel4,
99
91
  };
100
92
 
101
93
  return offers.map((offer): FacebookShopItem => ({
102
94
  ...base,
103
- id: this.tag(`${vehicleId}_${offer.offerType}`, true),
104
- title: this.tag(offer.title, true),
105
- description: this.tag(offer.description, true),
106
- offer_type: this.tag(offer.offerType, false),
107
- ...(offer.disclaimer ? { offer_disclaimer: this.tag(offer.disclaimer, false) } : {}),
95
+ vehicle_offer_id: `${vehicleId}_${offer.offerType}`,
96
+ title: offer.title,
97
+ offer_description: offer.description,
98
+ offer_type: offer.offerType,
99
+ ...(offer.disclaimer ? { offer_disclaimer: offer.disclaimer } : {}),
108
100
  ...(offer.financials ? this.financialTags(offer.financials) : {}),
109
- } as FacebookShopItem));
101
+ }));
110
102
  }
111
103
 
112
104
  private buildOffers(car: DataSchemes.Car, common: { make: string; model: string; price: number }): Offer[] {
@@ -213,20 +205,15 @@ export class FacebookShopTransformer {
213
205
 
214
206
  private financialTags(financials: OfferFinancials): Partial<FacebookShopItem> {
215
207
  return {
216
- monthly_payment: this.tag(financials.monthlyPayment, false),
217
- down_payment: this.tag(financials.downPayment, false),
218
- term_length: this.tag(financials.termLength, false),
219
- apr: this.tag(financials.apr, false),
220
- final_payment: this.tag(financials.finalPayment, false),
221
- total_amount: this.tag(financials.totalAmount, false),
222
- net_loan_amount: this.tag(financials.netLoanAmount, false),
208
+ amount_price: `${financials.monthlyPayment} EUR`,
209
+ amount_percentage: String(financials.apr),
210
+ amount_qualifier: AMOUNT_QUALIFIER_APR,
211
+ term_length: financials.termLength,
212
+ term_qualifier: TERM_QUALIFIER_MONTHS,
213
+ downpayment: `${financials.downPayment} EUR`,
223
214
  };
224
215
  }
225
216
 
226
- private tag(value: any, isGoogle: boolean): FacebookShopTag {
227
- return { value, isGoogle };
228
- }
229
-
230
217
  // lodash's get() only falls back to the default for an *undefined* path — an explicit
231
218
  // `null` stored on the Car document (a common Mongo pattern for "not set") passes
232
219
  // straight through and ends up rendering as an empty XML tag. Coalesce it here instead.
@@ -250,14 +237,8 @@ export class FacebookShopTransformer {
250
237
  return firstRegistration ? moment(firstRegistration * 1000).format('YYYY') : moment().format('YYYY');
251
238
  }
252
239
 
253
- private getCondition(car: DataSchemes.Car): string {
254
- const available = {
255
- selector_condition_new: 'new',
256
- selector_condition_used: 'used',
257
- selector_unknown: 'used',
258
- };
259
- const condition = get(car, 'mainData.condition', 'selector_unknown');
260
- return get(available, condition);
240
+ private getAvailability(car: DataSchemes.Car): string {
241
+ return get(car, 'state.isOnline', false) ? 'AVAILABLE' : 'NOT_AVAILABLE';
261
242
  }
262
243
 
263
244
  private getCarLink(car: DataSchemes.Car): string {
@@ -106,8 +106,7 @@ export class FbTransformer {
106
106
  make: toString(get(car, 'mainData.make', '')),
107
107
  model: toString(get(car, 'mainData.model', '')),
108
108
  trim: this.getTrim(car),
109
- image_link: image_links[0],
110
- additional_image_link: image_links.slice(1, 21), // Meta allows max 20 additional images
109
+ image: image_links.slice(0, 20), // Meta caps the whole image array at 20 items
111
110
  year: toString(year),
112
111
  mileage: {
113
112
  value: this.getMileage(car),
@@ -121,7 +120,7 @@ export class FbTransformer {
121
120
  price: this.getPrice(car),
122
121
  exterior_color: this.getExteriorColor(car),
123
122
  interior_color: this.getInteriorColor(car),
124
- condition: this.mapCondition(car),
123
+ state_of_vehicle: this.mapCondition(car),
125
124
  energy_efficiency_class_eu: this.getEnergyEfficiencyClass(car),
126
125
  vehicle_specifications: this.getVehicleSpecifications(car),
127
126
  };
@@ -395,16 +394,16 @@ export class FbTransformer {
395
394
 
396
395
  private mapCondition(car: DataSchemes.Car): string {
397
396
  const available = {
398
- selector_condition_new: 'new',
399
- selector_condition_used: 'used',
400
- selector_unknown: 'used',
397
+ selector_condition_new: 'New',
398
+ selector_condition_used: 'Used',
399
+ selector_unknown: 'Used',
401
400
  };
402
401
  const condition = get(car, 'mainData.condition', 'selector_unknown');
403
402
  return get(available, condition);
404
403
  }
405
404
 
406
405
  private mapAvailability(car: DataSchemes.Car): string {
407
- return get(car, 'state.isOnline', false) ? 'in stock' : 'out of stock';
406
+ return get(car, 'state.isOnline', false) ? 'available' : 'not_available';
408
407
  }
409
408
 
410
409
  private getEnergyEfficiencyClass(car: DataSchemes.Car): string {
@@ -1,13 +1,17 @@
1
- import { escape, get, isNumber, join, round, toSafeInteger, toString, trim, truncate } from 'lodash';
1
+ import { escape, get, includes, isNumber, join, round, toSafeInteger, toString, trim, truncate } from 'lodash';
2
2
  import { CarDescriptionFactory, DescriptionTypeEnum } from '@bytebrand/car-description';
3
3
  import { DataSchemes } from '@bytebrand/car-schema';
4
4
  import { TranslatorExtended } from '@bytebrand/schema-tools';
5
5
  import { de, deVehicleDetailsPage, deVehicleProps } from '@bytebrand/i18n-dictionaries';
6
6
  import { ImboImageResponseInterface } from '@bytebrand/chunkable';
7
7
  import { Injectable } from '@nestjs/common';
8
- import { ConfigService, ImagesService, TransformerService, UserService } from '../services';
8
+ import { ConfigService, ImagesService, MappingService, TransformerService, UserService } from '../services';
9
9
  import { GoogleXmlItem } from '../interfaces';
10
10
  import { isValidVin } from '../utils';
11
+ import {
12
+ META_PUSH_PRIORITY_ALLOWED_VALUES,
13
+ META_PUSH_PRIORITY_STANDARD,
14
+ } from '../constants/fb.constants';
11
15
 
12
16
  const GOOGLE_MAX_TRIM_LENGTH = 50;
13
17
  const TIMESTAMP_FIRST_YEAR = 1970;
@@ -21,6 +25,7 @@ export class GoogleTransformer {
21
25
  private configService: ConfigService,
22
26
  private imageService: ImagesService,
23
27
  private readonly transformService: TransformerService,
28
+ private readonly mappingService: MappingService,
24
29
  ) {
25
30
  const dict = { ...de, ...deVehicleProps, ...deVehicleDetailsPage };
26
31
  this.translator = new TranslatorExtended(dict);
@@ -50,6 +55,8 @@ export class GoogleTransformer {
50
55
  ...transformedImages.feat
51
56
  ]
52
57
 
58
+ const ownerId = get(car, 'metaData.ownerId', null);
59
+
53
60
  const item: GoogleXmlItem = {
54
61
  google_product_category: '916',
55
62
  vehicle_fulfillment: {
@@ -92,11 +99,12 @@ export class GoogleTransformer {
92
99
  description: this.processText((await this.getDescription(car))),
93
100
  identifier_exists: 'yes',
94
101
  availability: 'in_stock',
102
+ user_id: ownerId,
103
+ custom_label_4: await this.getMetaPushPriority(ownerId),
95
104
  // custom_label_0: '',
96
105
  // custom_label_1: '',
97
106
  // custom_label_2: '',
98
107
  // custom_label_3: '',
99
- // custom_label_4: '',
100
108
 
101
109
  // availability: this.getAvailability(car),
102
110
  // sale_price: this.getPrice(car),
@@ -131,6 +139,13 @@ export class GoogleTransformer {
131
139
  return item;
132
140
  }
133
141
 
142
+ private async getMetaPushPriority(ownerId: string): Promise<string> {
143
+ const priorities = await this.mappingService.getMetaPushPriorityMapping();
144
+ const entry = priorities.find(priority => priority.dealer_id === ownerId);
145
+ const value = get(entry, 'meta_push_priority', '');
146
+ return includes(META_PUSH_PRIORITY_ALLOWED_VALUES, value) ? value : META_PUSH_PRIORITY_STANDARD;
147
+ }
148
+
134
149
  private checkCarValidity(car: DataSchemes.Car, images: ImboImageResponseInterface[]) {
135
150
  if (images.length === 0)
136
151
  return false