@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.
- package/dist/constants/fb.constants.d.ts +5 -3
- package/dist/constants/fb.constants.js +6 -4
- package/dist/constants/fb.constants.js.map +1 -1
- package/dist/exporters/facebook-shop.exporter.js +6 -4
- package/dist/exporters/facebook-shop.exporter.js.map +1 -1
- package/dist/formats/facebook-shop.builder.d.ts +3 -3
- package/dist/formats/facebook-shop.builder.js +21 -15
- package/dist/formats/facebook-shop.builder.js.map +1 -1
- package/dist/formats/fb-xml.builder.js +2 -2
- package/dist/formats/fb-xml.builder.js.map +1 -1
- package/dist/interfaces/export-item.interface.d.ts +21 -35
- package/dist/services/rules.service.d.ts +1 -1
- package/dist/transformers/facebook-shop.transformer.d.ts +1 -2
- package/dist/transformers/facebook-shop.transformer.js +22 -42
- package/dist/transformers/facebook-shop.transformer.js.map +1 -1
- package/dist/transformers/fb.transformer.js +6 -7
- package/dist/transformers/fb.transformer.js.map +1 -1
- package/dist/transformers/google.transformer.d.ts +4 -2
- package/dist/transformers/google.transformer.js +15 -2
- package/dist/transformers/google.transformer.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
- package/src/constants/fb.constants.ts +8 -3
- package/src/exporters/facebook-shop.exporter.ts +6 -4
- package/src/formats/facebook-shop.builder.ts +59 -46
- package/src/formats/fb-xml.builder.ts +2 -2
- package/src/interfaces/export-item.interface.ts +25 -37
- package/src/transformers/facebook-shop.transformer.ts +26 -45
- package/src/transformers/fb.transformer.ts +6 -7
- package/src/transformers/google.transformer.ts +18 -3
package/package.json
CHANGED
|
@@ -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 = '
|
|
13
|
-
leasing = '
|
|
14
|
-
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
|
|
28
|
-
|
|
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
|
|
50
|
+
await facebookShopXmlBuilder.addItem(item);
|
|
49
51
|
}
|
|
50
52
|
this.carService.counter.countCar(data.images);
|
|
51
53
|
}
|
|
52
54
|
});
|
|
53
55
|
|
|
54
|
-
await
|
|
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
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
item
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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 === '
|
|
20
|
-
return data.map((
|
|
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
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
104
|
-
title:
|
|
105
|
-
|
|
106
|
-
offer_type:
|
|
107
|
-
...(offer.disclaimer ? { offer_disclaimer:
|
|
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
|
-
}
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
|
254
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: '
|
|
399
|
-
selector_condition_used: '
|
|
400
|
-
selector_unknown: '
|
|
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) ? '
|
|
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
|