@bytebrand/export-cars 1.10.7 → 1.10.9
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/exporters/meinstadt.exporter.js +2 -1
- package/dist/exporters/meinstadt.exporter.js.map +1 -1
- package/dist/interfaces/export-item.interface.d.ts +1 -1
- package/dist/services/images.service.d.ts +4 -2
- package/dist/services/images.service.js +39 -52
- package/dist/services/images.service.js.map +1 -1
- package/dist/transformers/facebook-shop.transformer.js +1 -3
- package/dist/transformers/facebook-shop.transformer.js.map +1 -1
- package/dist/transformers/meinstadt.transformer.d.ts +6 -3
- package/dist/transformers/meinstadt.transformer.js +11 -12
- package/dist/transformers/meinstadt.transformer.js.map +1 -1
- package/dist/transformers/mobile.transformer.d.ts +6 -8
- package/dist/transformers/mobile.transformer.js +15 -47
- package/dist/transformers/mobile.transformer.js.map +1 -1
- package/dist/transformers/ooyyo.transformer.js +2 -2
- package/dist/transformers/ooyyo.transformer.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/exporters/meinstadt.exporter.ts +2 -2
- package/src/interfaces/export-item.interface.ts +1 -1
- package/src/services/images.service.ts +47 -61
- package/src/transformers/facebook-shop.transformer.ts +1 -3
- package/src/transformers/meinstadt.transformer.ts +16 -13
- package/src/transformers/mobile.transformer.ts +17 -46
- package/src/transformers/ooyyo.transformer.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytebrand/export-cars",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.9",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "bytebrand",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=14.0.0"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "656a154e9410d0bccd17b7e9070b179747fd6e4f"
|
|
64
64
|
}
|
|
@@ -33,10 +33,10 @@ export class MeinstadtExporter implements Exporter {
|
|
|
33
33
|
|
|
34
34
|
let firstCar = true;
|
|
35
35
|
await this.loaderService.process(async (chunk: FsChunkInterface) => {
|
|
36
|
-
|
|
36
|
+
chunk.data = chunk.data.filter(e => this.carService.filterCar(e, this.rulesService.rules));
|
|
37
37
|
|
|
38
38
|
for (const data of chunk.data) {
|
|
39
|
-
const car = await meinstadtTransformer.transform(
|
|
39
|
+
const car = await meinstadtTransformer.transform(data);
|
|
40
40
|
await meinstadtJsonBuilder.addItem(car as MeinstadtJsonItem, firstCar);
|
|
41
41
|
this.carService.counter.countCar(data.images);
|
|
42
42
|
|
|
@@ -14,6 +14,12 @@ import { ImageType } from '../enums';
|
|
|
14
14
|
|
|
15
15
|
@Injectable()
|
|
16
16
|
export class ImagesService {
|
|
17
|
+
private readonly DEFAULT_IMAGES = [
|
|
18
|
+
'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg',
|
|
19
|
+
'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg',
|
|
20
|
+
'https://images.auto.de/carimage/noimage/pFyfBsqBHEso/large-cached.jpeg',
|
|
21
|
+
];
|
|
22
|
+
|
|
17
23
|
constructor(private readonly configService: ConfigService, private readonly userService: UserService) { }
|
|
18
24
|
|
|
19
25
|
async getImages(
|
|
@@ -24,63 +30,22 @@ export class ImagesService {
|
|
|
24
30
|
if (imageType === ImageType.default) {
|
|
25
31
|
return this.getDefaultImages(car, images);
|
|
26
32
|
} else {
|
|
27
|
-
|
|
28
|
-
return await this.getMarketingImages(images, carId);
|
|
33
|
+
return await this.getMarketingImages(car, images);
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
getDefaultImages(car: DataSchemes.Car, images: ImboImageResponseInterface[]): Array<string> {
|
|
33
|
-
const defaultImages = [
|
|
34
|
-
'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg',
|
|
35
|
-
'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg',
|
|
36
|
-
'https://images.auto.de/carimage/noimage/gY1zF8PXzH2W/large-cached.jpeg',
|
|
37
|
-
'https://images.auto.de/carimage/noimage/pFyfBsqBHEso/large-cached.jpeg',
|
|
38
|
-
];
|
|
39
|
-
|
|
40
38
|
if (!isNotEmptyArray(images)) {
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const firstImageId = get(car, 'metaData.mainImageId', null);
|
|
45
|
-
const secondImageId = get(car, 'metaData.secImageId', null);
|
|
46
|
-
const thirdImageId = get(car, 'metaData.thirdImageId', null);
|
|
47
|
-
|
|
48
|
-
if (firstImageId) {
|
|
49
|
-
images.forEach((image, index) => {
|
|
50
|
-
if (firstImageId === image?.imageIdentifier) {
|
|
51
|
-
const tmp = images[index];
|
|
52
|
-
images[index] = images[0];
|
|
53
|
-
images[0] = tmp;
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (secondImageId) {
|
|
59
|
-
images.forEach((image, index) => {
|
|
60
|
-
if (secondImageId === image?.imageIdentifier) {
|
|
61
|
-
const tmp = images[index];
|
|
62
|
-
images[index] = images[1];
|
|
63
|
-
images[1] = tmp;
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (thirdImageId) {
|
|
69
|
-
images.forEach((image, index) => {
|
|
70
|
-
if (thirdImageId === image?.imageIdentifier) {
|
|
71
|
-
const tmp = images[index];
|
|
72
|
-
images[index] = images[2];
|
|
73
|
-
images[2] = tmp;
|
|
74
|
-
}
|
|
75
|
-
});
|
|
39
|
+
return this.DEFAULT_IMAGES;
|
|
76
40
|
}
|
|
77
41
|
|
|
78
|
-
|
|
42
|
+
this.sortImages(images, car);
|
|
43
|
+
const transformedImages = this.generateImageLinks(images, get(car, '_id'));
|
|
79
44
|
|
|
80
|
-
const transformedImages = this.generateImageLinks(images.filter(i => i), carId);
|
|
81
45
|
if (transformedImages.length < 17) {
|
|
82
|
-
transformedImages.push(...
|
|
46
|
+
transformedImages.push(...this.DEFAULT_IMAGES);
|
|
83
47
|
}
|
|
48
|
+
|
|
84
49
|
return transformedImages;
|
|
85
50
|
}
|
|
86
51
|
|
|
@@ -90,40 +55,34 @@ export class ImagesService {
|
|
|
90
55
|
});
|
|
91
56
|
}
|
|
92
57
|
|
|
93
|
-
async getMarketingImages(
|
|
58
|
+
async getMarketingImages(car: DataSchemes.Car, images: ImboImageResponseInterface[]): Promise<string[]> {
|
|
94
59
|
const imageUrl = this.configService.config.marketingImageUrl;
|
|
95
|
-
const transformedImages = this.transformImagesArrayIntoObject(images);
|
|
96
60
|
|
|
61
|
+
const transformedImages = this.transformImagesArrayIntoObject(images);
|
|
97
62
|
const config = await this.userService.getMarketingImageConfig(this.configService.config.marketingImageConfigId);
|
|
98
63
|
const marketingImageConfigs = config.marketingImages.map(i => ({ marketingImageCodes: i.imageCodes }));
|
|
99
64
|
|
|
100
|
-
const defImages = [
|
|
101
|
-
'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg',
|
|
102
|
-
'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg',
|
|
103
|
-
'https://images.auto.de/carimage/noimage/gY1zF8PXzH2W/large-cached.jpeg',
|
|
104
|
-
'https://images.auto.de/carimage/noimage/pFyfBsqBHEso/large-cached.jpeg',
|
|
105
|
-
];
|
|
106
|
-
|
|
107
65
|
const imageUrls = [];
|
|
108
|
-
|
|
109
66
|
for (let i = 0; i < marketingImageConfigs.length; i++) {
|
|
110
67
|
const marketingImage = marketingImageConfigs[i];
|
|
111
68
|
for (let i = 0; i < marketingImage.marketingImageCodes.length; i++) {
|
|
112
69
|
const imageCode = marketingImage.marketingImageCodes[i];
|
|
113
70
|
const imageId = transformedImages[imageCode];
|
|
114
71
|
if (imageId) {
|
|
115
|
-
imageUrls.push(this.
|
|
72
|
+
imageUrls.push(this.getImagePathWithExtension(imageUrl, get(car, '_id', ''), imageId, config));
|
|
116
73
|
break;
|
|
117
74
|
}
|
|
118
75
|
}
|
|
119
76
|
}
|
|
77
|
+
|
|
120
78
|
if (imageUrls.length < FB_MAX_IMAGE_COUNT_FOR_DEAFULT) {
|
|
121
|
-
imageUrls.push(...
|
|
79
|
+
imageUrls.push(...this.DEFAULT_IMAGES);
|
|
122
80
|
}
|
|
81
|
+
|
|
123
82
|
return imageUrls;
|
|
124
83
|
}
|
|
125
84
|
|
|
126
|
-
private transformImagesArrayIntoObject(images:
|
|
85
|
+
private transformImagesArrayIntoObject(images: ImboImageResponseInterface[]) {
|
|
127
86
|
const result: { [imageCode: string]: string } = {};
|
|
128
87
|
images.forEach(image => {
|
|
129
88
|
const imageCode = image.imageCodePredicted.split('-')[0];
|
|
@@ -136,7 +95,7 @@ export class ImagesService {
|
|
|
136
95
|
return `${imageUrl}/${[carId[0], carId[1], carId[2], carId].join('/')}`;
|
|
137
96
|
}
|
|
138
97
|
|
|
139
|
-
protected
|
|
98
|
+
protected getImagePathWithExtension(
|
|
140
99
|
imageUrl: string,
|
|
141
100
|
carId: string,
|
|
142
101
|
imageId: string,
|
|
@@ -145,4 +104,31 @@ export class ImagesService {
|
|
|
145
104
|
const { channelCode, imageExtension } = config;
|
|
146
105
|
return `${this.getChannelPath(imageUrl, carId)}/${channelCode.replace(/ /g, '-')}-${imageId}.${imageExtension}`;
|
|
147
106
|
}
|
|
107
|
+
|
|
108
|
+
private sortImages(images: ImboImageResponseInterface[], car: DataSchemes.Car): void {
|
|
109
|
+
const firstImageId = get(car, 'metaData.mainImageId', null);
|
|
110
|
+
const secondImageId = get(car, 'metaData.secImageId', null);
|
|
111
|
+
const thirdImageId = get(car, 'metaData.thirdImageId', null);
|
|
112
|
+
|
|
113
|
+
if (firstImageId) {
|
|
114
|
+
images.forEach((image, index) => {
|
|
115
|
+
if (firstImageId === image?.imageIdentifier) {
|
|
116
|
+
const tmp = images[index];
|
|
117
|
+
images[index] = images[0];
|
|
118
|
+
images[0] = tmp;
|
|
119
|
+
}
|
|
120
|
+
if (secondImageId === image?.imageIdentifier) {
|
|
121
|
+
const tmp = images[index];
|
|
122
|
+
images[index] = images[1];
|
|
123
|
+
images[1] = tmp;
|
|
124
|
+
}
|
|
125
|
+
if (thirdImageId === image?.imageIdentifier) {
|
|
126
|
+
const tmp = images[index];
|
|
127
|
+
images[index] = images[2];
|
|
128
|
+
images[2] = tmp;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
images.filter(i => i); // sometimes thirdImageId exists but image is not
|
|
132
|
+
}
|
|
133
|
+
}
|
|
148
134
|
}
|
|
@@ -56,11 +56,9 @@ export class FacebookShopTransformer {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
private getTitle(car: DataSchemes.Car): string {
|
|
59
|
-
const year = toString(get(car, 'mainData.constructionYear', ''));
|
|
60
59
|
const make = toString(get(car, 'mainData.make', ''));
|
|
61
60
|
const model = toString(get(car, 'mainData.model', ''));
|
|
62
|
-
|
|
63
|
-
return trim(escape(join([year, make, model, subModel], ' ')));
|
|
61
|
+
return trim(escape(join([make, model], ' ')));
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
private getCondition(car: DataSchemes.Car): string {
|
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
import { get, toString } from 'lodash';
|
|
2
|
-
import { DataSchemes } from '@bytebrand/car-schema';
|
|
3
2
|
|
|
4
|
-
import { de } from '@bytebrand/i18n-dictionaries';
|
|
5
3
|
import { Injectable } from '@nestjs/common';
|
|
6
|
-
|
|
4
|
+
|
|
5
|
+
import { ImboImageResponseInterface } from '@bytebrand/chunkable';
|
|
6
|
+
import { DataSchemes } from '@bytebrand/car-schema';
|
|
7
|
+
import { de } from '@bytebrand/i18n-dictionaries';
|
|
8
|
+
|
|
9
|
+
import { ConfigService, ImagesService } from '../services';
|
|
7
10
|
import { MeinstadtJsonItem } from '../interfaces';
|
|
8
11
|
|
|
12
|
+
|
|
9
13
|
@Injectable()
|
|
10
14
|
export class MeinstadtTransformer {
|
|
11
|
-
constructor(private configService: ConfigService) {}
|
|
15
|
+
constructor(private configService: ConfigService, private readonly imageService: ImagesService) {}
|
|
16
|
+
|
|
17
|
+
async transform({ car, images }: { car: DataSchemes.Car, images: ImboImageResponseInterface[] }): Promise<Partial<MeinstadtJsonItem>> {
|
|
18
|
+
const carImages = await this.imageService.getImages(car, images, this.configService.config.imageType);
|
|
19
|
+
|
|
20
|
+
const carId = toString(get(car, '_id', null));
|
|
12
21
|
|
|
13
|
-
async transform({ car }: { car: DataSchemes.Car }): Promise<Partial<MeinstadtJsonItem>> {
|
|
14
|
-
const autodeId = toString(get(car, '_id', null));
|
|
15
|
-
const imageId = get(car, 'metaData.mainImageId', null);
|
|
16
|
-
const imageUrl = imageId
|
|
17
|
-
? `https://images.auto.de/carimage/${car._id}/${imageId}/large-cached.webp`
|
|
18
|
-
: 'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg';
|
|
19
22
|
return {
|
|
20
23
|
id: get(car, 'metaData.vehicleId', null),
|
|
21
24
|
make: get(car, 'mainData.make', null),
|
|
22
25
|
model: get(car, 'mainData.model', null),
|
|
23
26
|
cpc: get(this.configService.config, 'cpc', '0.08'),
|
|
24
|
-
listingUrl: `https://www.${this.configService.config.domain}/search/vehicle/${
|
|
27
|
+
listingUrl: `https://www.${this.configService.config.domain}/search/vehicle/${carId}?source=classifieds&medium=listing&campaign=meinestadt`,
|
|
25
28
|
title: this.getTitle(car),
|
|
26
29
|
accidentFree: get(car, 'mainData.accidentDamaged', null),
|
|
27
30
|
mileage: get(car, 'mainData.mileage', null),
|
|
@@ -41,10 +44,10 @@ export class MeinstadtTransformer {
|
|
|
41
44
|
emissionSticker: this.translate(get(car, 'environmentEmissions.emissionSticker', null)),
|
|
42
45
|
fuelType: this.translate(get(car, 'consumption.fuel', null)),
|
|
43
46
|
'transmissionType/transmission': this.translate(get(car, 'driveSuspension.gearbox', null)),
|
|
44
|
-
imagesCount:
|
|
47
|
+
imagesCount: carImages.length,
|
|
45
48
|
'customerType/sellerType': 'Händler',
|
|
46
49
|
usageState: this.translate(this.getUsageState(car)),
|
|
47
|
-
images:
|
|
50
|
+
images: carImages,
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
53
|
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import { get, isEmpty, isNil, set, toString, upperFirst } from 'lodash';
|
|
2
|
+
|
|
1
3
|
import { Injectable } from '@nestjs/common';
|
|
4
|
+
|
|
5
|
+
import { CarDescriptionFactory, DescriptionTypeEnum } from '@bytebrand/car-description';
|
|
6
|
+
import { ImboImageResponseInterface } from '@bytebrand/chunkable';
|
|
7
|
+
import { LoggerService } from '@bytebrand/cronicle-helper';
|
|
2
8
|
import { DataSchemes } from '@bytebrand/car-schema';
|
|
3
|
-
|
|
4
|
-
import { MappingService } from '../services
|
|
9
|
+
|
|
10
|
+
import { MappingService, UserService, ImagesService } from '../services';
|
|
5
11
|
import { MappingRules } from '../interfaces/mapping-rules.interface';
|
|
6
|
-
import { UserService } from '../services/user.service';
|
|
7
|
-
import { CarDescriptionFactory, DescriptionTypeEnum } from '@bytebrand/car-description';
|
|
8
|
-
import { ConfigService } from '../services/config.service';
|
|
9
12
|
import { isNotEmptyArray } from '../utils/validator.utils';
|
|
10
|
-
import {
|
|
13
|
+
import { ConfigService } from '../services';
|
|
14
|
+
|
|
11
15
|
|
|
12
16
|
const vinGenerator = require('vin-generator');
|
|
13
17
|
|
|
@@ -19,9 +23,10 @@ export class MobileTransformer {
|
|
|
19
23
|
private mappingService: MappingService,
|
|
20
24
|
private userService: UserService,
|
|
21
25
|
private configService: ConfigService,
|
|
22
|
-
|
|
26
|
+
private imagesService: ImagesService,
|
|
27
|
+
) { }
|
|
23
28
|
|
|
24
|
-
async transform(carData: DataSchemes.Car, images:
|
|
29
|
+
async transform(carData: DataSchemes.Car, images: ImboImageResponseInterface[]): Promise<unknown> {
|
|
25
30
|
this.currentCar = carData;
|
|
26
31
|
const transformedCarData = {};
|
|
27
32
|
const rules = await this.mappingService.getRules();
|
|
@@ -347,17 +352,11 @@ export class MobileTransformer {
|
|
|
347
352
|
return `https://www.${this.configService.config.domain}${car._id}?source=classifieds&medium=listing&campaign=${this.configService.config.campaign}`;
|
|
348
353
|
}
|
|
349
354
|
|
|
350
|
-
private getImages(car: DataSchemes.Car, images
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
res = this.getImagesField(car._id, get(car, 'metaData.mainImageId', null), images);
|
|
354
|
-
} catch (e) {
|
|
355
|
-
LoggerService.error(e);
|
|
356
|
-
throw e;
|
|
357
|
-
}
|
|
355
|
+
private async getImages(car: DataSchemes.Car, images): Promise<string | null> {
|
|
356
|
+
const transformedImages = await this.imagesService.getImages(car, images, this.configService.config.imageType);
|
|
358
357
|
let imagesAsALine;
|
|
359
|
-
if (isNotEmptyArray(
|
|
360
|
-
imagesAsALine =
|
|
358
|
+
if (isNotEmptyArray(transformedImages)) {
|
|
359
|
+
imagesAsALine = transformedImages.map((el: string) => el).join(';');
|
|
361
360
|
}
|
|
362
361
|
return imagesAsALine || null;
|
|
363
362
|
}
|
|
@@ -474,32 +473,4 @@ export class MobileTransformer {
|
|
|
474
473
|
}
|
|
475
474
|
return mileage.toString();
|
|
476
475
|
}
|
|
477
|
-
|
|
478
|
-
private getImagesField(carId: string, mainImageId: string, images: unknown[]): { url: string }[] {
|
|
479
|
-
const defImages = [
|
|
480
|
-
{ url: 'https://images.auto.de/carimage/noimage/7pNvWELuWhZX/large-cached.jpeg' },
|
|
481
|
-
{ url: 'https://images.auto.de/carimage/noimage/GvyXmrpaf1D6/large-cached.jpeg' },
|
|
482
|
-
{ url: 'https://images.auto.de/carimage/noimage/gY1zF8PXzH2W/large-cached.jpeg' },
|
|
483
|
-
{ url: 'https://images.auto.de/carimage/noimage/pFyfBsqBHEso/large-cached.jpeg' },
|
|
484
|
-
];
|
|
485
|
-
if (isNotEmptyArray(images)) {
|
|
486
|
-
return images.sort(this.setMainImageFirst(mainImageId)).map((image: any) => {
|
|
487
|
-
return { url: this.buildLargeImageUrl(carId, image.imageIdentifier) };
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
return defImages;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
private buildLargeImageUrl(carId: string, imageId: string): string {
|
|
494
|
-
const format = this.configService.config.campaign === 'eauto' ? 'jpeg' : 'webp';
|
|
495
|
-
return `${this.configService.config.imageUrl}/${carId}/${imageId}/large-cached.${format}`;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
private setMainImageFirst(mainImageId: string): (current: any, next: any) => number {
|
|
499
|
-
return (current: any, next: any): number => {
|
|
500
|
-
if (current.imageIdentifier === mainImageId) return -1;
|
|
501
|
-
if (next.imageIdentifier === mainImageId) return 1;
|
|
502
|
-
return 0;
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
476
|
}
|
|
@@ -17,7 +17,7 @@ export class OoyyoTransformer {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
async transform(car: DataSchemes.Car, imboImages: ImboImageResponseInterface[]): Promise<OoyyoXmlItem> {
|
|
20
|
-
const
|
|
20
|
+
const carId = toString(get(car, '_id', ''));
|
|
21
21
|
const creationDate = get(car, 'metaData.creationDate') as number;
|
|
22
22
|
const constructionYear = get(car, 'mainData.constructionYear') as number;
|
|
23
23
|
const firstRegistration = get(car, 'mainData.firstRegistration') as number;
|
|
@@ -29,7 +29,7 @@ export class OoyyoTransformer {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
return {
|
|
32
|
-
url: `https://www.${this.configService.config.domain}/search/vehicle/${
|
|
32
|
+
url: `https://www.${this.configService.config.domain}/search/vehicle/${carId}?source=classifieds&medium=listing&campaign=ooyyo`,
|
|
33
33
|
title: this.getTitle(car),
|
|
34
34
|
content: trim(toString(get(car, 'offer.offerDescription', ''))),
|
|
35
35
|
price: toString(get(car, 'price.currentSalesPrice', '')),
|