@bytebrand/export-cars 1.22.28 → 1.22.30
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/configs/config.d.ts +1 -0
- package/dist/configs/config.js +2 -0
- package/dist/configs/config.js.map +1 -1
- package/dist/constants/fb.constants.d.ts +2 -0
- package/dist/constants/fb.constants.js +3 -1
- package/dist/constants/fb.constants.js.map +1 -1
- package/dist/interfaces/dealers-mapping.interface.d.ts +5 -0
- package/dist/interfaces/params.interface.d.ts +1 -0
- package/dist/services/mapping.service.d.ts +3 -1
- package/dist/services/mapping.service.js +15 -0
- package/dist/services/mapping.service.js.map +1 -1
- package/dist/transformers/fb.transformer.d.ts +4 -2
- package/dist/transformers/fb.transformer.js +14 -2
- package/dist/transformers/fb.transformer.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/converter.utils.d.ts +1 -0
- package/dist/utils/converter.utils.js +51 -1
- package/dist/utils/converter.utils.js.map +1 -1
- package/package.json +1 -1
- package/src/configs/config.ts +2 -0
- package/src/constants/fb.constants.ts +2 -0
- package/src/interfaces/dealers-mapping.interface.ts +6 -0
- package/src/interfaces/params.interface.ts +1 -0
- package/src/services/mapping.service.ts +18 -1
- package/src/transformers/fb.transformer.ts +14 -1
- package/src/utils/converter.utils.ts +52 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.xmlStringReplacer = exports.convertToCSV = void 0;
|
|
3
|
+
exports.parseCsvToObjects = exports.xmlStringReplacer = exports.convertToCSV = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
function convertToCSV(data) {
|
|
6
6
|
const converted = [];
|
|
@@ -16,4 +16,54 @@ const xmlStringReplacer = (str) => {
|
|
|
16
16
|
return typeof str === 'string' ? str.replace(/&/g, '&').replace(/[<>]/g, '') : '';
|
|
17
17
|
};
|
|
18
18
|
exports.xmlStringReplacer = xmlStringReplacer;
|
|
19
|
+
function parseCsvToObjects(csv) {
|
|
20
|
+
const rows = [];
|
|
21
|
+
let row = [];
|
|
22
|
+
let field = '';
|
|
23
|
+
let inQuotes = false;
|
|
24
|
+
for (let i = 0; i < csv.length; i += 1) {
|
|
25
|
+
const char = csv[i];
|
|
26
|
+
if (inQuotes) {
|
|
27
|
+
if (char === '"' && csv[i + 1] === '"') {
|
|
28
|
+
field += '"';
|
|
29
|
+
i += 1;
|
|
30
|
+
}
|
|
31
|
+
else if (char === '"') {
|
|
32
|
+
inQuotes = false;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
field += char;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else if (char === '"') {
|
|
39
|
+
inQuotes = true;
|
|
40
|
+
}
|
|
41
|
+
else if (char === ',') {
|
|
42
|
+
row.push(field);
|
|
43
|
+
field = '';
|
|
44
|
+
}
|
|
45
|
+
else if (char === '\n') {
|
|
46
|
+
row.push(field);
|
|
47
|
+
rows.push(row);
|
|
48
|
+
row = [];
|
|
49
|
+
field = '';
|
|
50
|
+
}
|
|
51
|
+
else if (char !== '\r') {
|
|
52
|
+
field += char;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (field.length || row.length) {
|
|
56
|
+
row.push(field);
|
|
57
|
+
rows.push(row);
|
|
58
|
+
}
|
|
59
|
+
const [header, ...dataRows] = rows.filter(r => r.some(cell => cell.trim() !== ''));
|
|
60
|
+
if (!header) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
return dataRows.map(dataRow => header.reduce((acc, key, idx) => {
|
|
64
|
+
acc[key.trim()] = (dataRow[idx] ?? '').trim();
|
|
65
|
+
return acc;
|
|
66
|
+
}, {}));
|
|
67
|
+
}
|
|
68
|
+
exports.parseCsvToObjects = parseCsvToObjects;
|
|
19
69
|
//# sourceMappingURL=converter.utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"converter.utils.js","sourceRoot":"","sources":["../../src/utils/converter.utils.ts"],"names":[],"mappings":";;;AAAA,mCAA6B;AAE7B,SAAgB,YAAY,CAAC,IAAa;IACxC,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QAC/B,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAa,CAAC;QAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;QAChE,IAAA,YAAG,EAAC,SAAS,EAAE,CAAC,EAAE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AARD,oCAQC;AAEM,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAU,EAAE;IACvD,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxF,CAAC,CAAC;AAFW,QAAA,iBAAiB,qBAE5B"}
|
|
1
|
+
{"version":3,"file":"converter.utils.js","sourceRoot":"","sources":["../../src/utils/converter.utils.ts"],"names":[],"mappings":";;;AAAA,mCAA6B;AAE7B,SAAgB,YAAY,CAAC,IAAa;IACxC,MAAM,SAAS,GAAG,EAAE,CAAC;IACrB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;QAC/B,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAa,CAAC;QAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;QAChE,IAAA,YAAG,EAAC,SAAS,EAAE,CAAC,EAAE,IAAI,QAAQ,GAAG,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AARD,oCAQC;AAEM,MAAM,iBAAiB,GAAG,CAAC,GAAW,EAAU,EAAE;IACvD,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxF,CAAC,CAAC;AAFW,QAAA,iBAAiB,qBAE5B;AAIF,SAAgB,iBAAiB,CAAI,GAAW;IAC9C,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,IAAI,GAAG,GAAa,EAAE,CAAC;IACvB,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE;QACtC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,QAAQ,EAAE;YACZ,IAAI,IAAI,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;gBACtC,KAAK,IAAI,GAAG,CAAC;gBACb,CAAC,IAAI,CAAC,CAAC;aACR;iBAAM,IAAI,IAAI,KAAK,GAAG,EAAE;gBACvB,QAAQ,GAAG,KAAK,CAAC;aAClB;iBAAM;gBACL,KAAK,IAAI,IAAI,CAAC;aACf;SACF;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE;YACvB,QAAQ,GAAG,IAAI,CAAC;SACjB;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE;YACvB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,KAAK,GAAG,EAAE,CAAC;SACZ;aAAM,IAAI,IAAI,KAAK,IAAI,EAAE;YACxB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACf,GAAG,GAAG,EAAE,CAAC;YACT,KAAK,GAAG,EAAE,CAAC;SACZ;aAAM,IAAI,IAAI,KAAK,IAAI,EAAE;YACxB,KAAK,IAAI,IAAI,CAAC;SACf;KACF;IACD,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE;QAC9B,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;KAChB;IAED,MAAM,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACnF,IAAI,CAAC,MAAM,EAAE;QACX,OAAO,EAAE,CAAC;KACX;IAED,OAAO,QAAQ,CAAC,GAAG,CACjB,OAAO,CAAC,EAAE,CACR,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9B,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAA4B,CAAM,CACxC,CAAC;AACJ,CAAC;AAhDD,8CAgDC"}
|
package/package.json
CHANGED
package/src/configs/config.ts
CHANGED
|
@@ -33,6 +33,7 @@ export class Config {
|
|
|
33
33
|
mappingSpreadsheetTitle: string;
|
|
34
34
|
dealersSpreadsheetId: string;
|
|
35
35
|
dealersSpreadsheetTitle: string;
|
|
36
|
+
metaPushPriorityCsvUrl: string;
|
|
36
37
|
|
|
37
38
|
protected environmentConfig = {
|
|
38
39
|
[Environment.DEVELOP]: {
|
|
@@ -65,6 +66,7 @@ export class Config {
|
|
|
65
66
|
this.mappingSpreadsheetId = '147qz9sTgs1wi13ua8YKa0IgfxAn1X_qH6LkGnAnzeyY';
|
|
66
67
|
this.dealersSpreadsheetId = '1gWrcA-uRTpna1h66Mbe2Y7NA0tIhlUaQXBcS4a_UzOw';
|
|
67
68
|
this.dealersSpreadsheetTitle = 'dealers_mapping';
|
|
69
|
+
this.metaPushPriorityCsvUrl = params.metaPushPriorityCsvUrl;
|
|
68
70
|
this.userActionsUrl = `https://www.${this.domain}/service/user-actions`;
|
|
69
71
|
this.imboUrl = `https://www.${this.domain}/service/image-imbo`;
|
|
70
72
|
this.imageUrl = `https://images.${this.domain}`;
|
|
@@ -5,3 +5,5 @@ export const DEFAULT_ZIP = '06796';
|
|
|
5
5
|
export const DEFAULT_CITY = 'Sandersdorf-Brehna';
|
|
6
6
|
export const DEFAULT_ADDR1 = 'Max-Planck-Str. 19';
|
|
7
7
|
export const TIMESTAMP_FIRST_YEAR = 1970;
|
|
8
|
+
export const META_PUSH_PRIORITY_STANDARD = 'standard';
|
|
9
|
+
export const META_PUSH_PRIORITY_ALLOWED_VALUES = ['user_priority_1', 'user_priority_2'];
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import axios from 'axios';
|
|
2
3
|
import { MappingRules } from '../interfaces/mapping-rules.interface';
|
|
3
4
|
import { GoogleSpreadsheet, GoogleSpreadsheetRow } from 'google-spreadsheet';
|
|
4
5
|
import { ConfigService } from './config.service';
|
|
5
|
-
import { DealersMapping } from '../interfaces/dealers-mapping.interface';
|
|
6
|
+
import { DealersMapping, MetaPushPriorityMapping } from '../interfaces/dealers-mapping.interface';
|
|
7
|
+
import { parseCsvToObjects } from '../utils';
|
|
6
8
|
|
|
7
9
|
@Injectable()
|
|
8
10
|
export class MappingService {
|
|
9
11
|
constructor(private configService: ConfigService) {}
|
|
10
12
|
private rules: MappingRules[];
|
|
11
13
|
private dealers: any;
|
|
14
|
+
private metaPushPriorities: MetaPushPriorityMapping[];
|
|
12
15
|
|
|
13
16
|
async getRules(): Promise<MappingRules[]> {
|
|
14
17
|
if (!this.rules) {
|
|
@@ -41,6 +44,20 @@ export class MappingService {
|
|
|
41
44
|
return this.dealers;
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
async getMetaPushPriorityMapping(): Promise<MetaPushPriorityMapping[]> {
|
|
48
|
+
if (!this.metaPushPriorities) {
|
|
49
|
+
const csvUrl = this.configService.config.metaPushPriorityCsvUrl;
|
|
50
|
+
if (!csvUrl) {
|
|
51
|
+
this.metaPushPriorities = [];
|
|
52
|
+
return this.metaPushPriorities;
|
|
53
|
+
}
|
|
54
|
+
// "Publish to the web" CSV export — a plain public GET, no Google API key/quota involved.
|
|
55
|
+
const { data } = await axios.get<string>(csvUrl, { responseType: 'text' });
|
|
56
|
+
this.metaPushPriorities = parseCsvToObjects<MetaPushPriorityMapping>(data);
|
|
57
|
+
}
|
|
58
|
+
return this.metaPushPriorities;
|
|
59
|
+
}
|
|
60
|
+
|
|
44
61
|
private rowsToRules(rows: GoogleSpreadsheetRow[]): MappingRules[] | DealersMapping[] {
|
|
45
62
|
return rows.map(row =>
|
|
46
63
|
Object.assign(
|
|
@@ -28,7 +28,7 @@ import { DataSchemes } from '@bytebrand/car-schema';
|
|
|
28
28
|
|
|
29
29
|
import { Description } from '../interfaces/description.interface';
|
|
30
30
|
import { FbDescription } from './fb-description.transformer';
|
|
31
|
-
import { ConfigService, ImagesService } from '../services';
|
|
31
|
+
import { ConfigService, ImagesService, MappingService } from '../services';
|
|
32
32
|
import { FbEquipment } from './fb-equipment.transformer';
|
|
33
33
|
import { isValidVin } from '../utils';
|
|
34
34
|
import { UserService } from 'src/services';
|
|
@@ -39,6 +39,8 @@ import {
|
|
|
39
39
|
DEFAULT_ZIP,
|
|
40
40
|
FB_MAX_TRIM_LENGTH,
|
|
41
41
|
FB_MIN_MILEAGES,
|
|
42
|
+
META_PUSH_PRIORITY_ALLOWED_VALUES,
|
|
43
|
+
META_PUSH_PRIORITY_STANDARD,
|
|
42
44
|
TIMESTAMP_FIRST_YEAR,
|
|
43
45
|
} from '../constants/fb.constants';
|
|
44
46
|
|
|
@@ -52,6 +54,7 @@ export class FbTransformer {
|
|
|
52
54
|
@Inject(CACHE_MANAGER) private cacheManager: Cache,
|
|
53
55
|
private readonly configService: ConfigService,
|
|
54
56
|
private readonly userService: UserService,
|
|
57
|
+
private readonly mappingService: MappingService,
|
|
55
58
|
) {
|
|
56
59
|
this.imagesService = new ImagesService(configService, userService);
|
|
57
60
|
const dict = { ...de, ...deVehicleProps, ...deVehicleDetailsPage };
|
|
@@ -70,6 +73,7 @@ export class FbTransformer {
|
|
|
70
73
|
}): Promise<unknown> {
|
|
71
74
|
const autodeId = toString(get(car, '_id', ''));
|
|
72
75
|
const year = this.getYear(car);
|
|
76
|
+
const ownerId = get(car, 'metaData.ownerId', null);
|
|
73
77
|
const dealerInfo = this.getDealerItems(car);
|
|
74
78
|
// console.time(`Address ${car._id}`);
|
|
75
79
|
const address = await this.getAddress(car, owner);
|
|
@@ -82,6 +86,8 @@ export class FbTransformer {
|
|
|
82
86
|
fb_page_id: '176306386132',
|
|
83
87
|
...address,
|
|
84
88
|
...dealerInfo,
|
|
89
|
+
user_id: ownerId,
|
|
90
|
+
custom_label_4: await this.getMetaPushPriority(ownerId),
|
|
85
91
|
vehicle_id: get(car, 'metaData.vehicleId', autodeId),
|
|
86
92
|
stock_number: autodeId,
|
|
87
93
|
availability: this.mapAvailability(car),
|
|
@@ -158,6 +164,13 @@ export class FbTransformer {
|
|
|
158
164
|
);
|
|
159
165
|
}
|
|
160
166
|
|
|
167
|
+
private async getMetaPushPriority(ownerId: string): Promise<string> {
|
|
168
|
+
const priorities = await this.mappingService.getMetaPushPriorityMapping();
|
|
169
|
+
const entry = priorities.find(priority => priority.user_id === ownerId);
|
|
170
|
+
const value = get(entry, 'meta_push_priority', '');
|
|
171
|
+
return includes(META_PUSH_PRIORITY_ALLOWED_VALUES, value) ? value : META_PUSH_PRIORITY_STANDARD;
|
|
172
|
+
}
|
|
173
|
+
|
|
161
174
|
private getDealerItems(car: DataSchemes.Car): {
|
|
162
175
|
dealer_communication_channel: string;
|
|
163
176
|
dealer_id: unknown;
|
|
@@ -13,3 +13,55 @@ export function convertToCSV(data: unknown): string {
|
|
|
13
13
|
export const xmlStringReplacer = (str: string): string => {
|
|
14
14
|
return typeof str === 'string' ? str.replace(/&/g, '&').replace(/[<>]/g, '') : '';
|
|
15
15
|
};
|
|
16
|
+
|
|
17
|
+
// Parses a "Publish to web" Google Sheets CSV export (RFC4180-ish, quoted fields may
|
|
18
|
+
// contain commas/newlines) into row arrays, then maps rows to objects keyed by header.
|
|
19
|
+
export function parseCsvToObjects<T>(csv: string): T[] {
|
|
20
|
+
const rows: string[][] = [];
|
|
21
|
+
let row: string[] = [];
|
|
22
|
+
let field = '';
|
|
23
|
+
let inQuotes = false;
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < csv.length; i += 1) {
|
|
26
|
+
const char = csv[i];
|
|
27
|
+
if (inQuotes) {
|
|
28
|
+
if (char === '"' && csv[i + 1] === '"') {
|
|
29
|
+
field += '"';
|
|
30
|
+
i += 1;
|
|
31
|
+
} else if (char === '"') {
|
|
32
|
+
inQuotes = false;
|
|
33
|
+
} else {
|
|
34
|
+
field += char;
|
|
35
|
+
}
|
|
36
|
+
} else if (char === '"') {
|
|
37
|
+
inQuotes = true;
|
|
38
|
+
} else if (char === ',') {
|
|
39
|
+
row.push(field);
|
|
40
|
+
field = '';
|
|
41
|
+
} else if (char === '\n') {
|
|
42
|
+
row.push(field);
|
|
43
|
+
rows.push(row);
|
|
44
|
+
row = [];
|
|
45
|
+
field = '';
|
|
46
|
+
} else if (char !== '\r') {
|
|
47
|
+
field += char;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (field.length || row.length) {
|
|
51
|
+
row.push(field);
|
|
52
|
+
rows.push(row);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const [header, ...dataRows] = rows.filter(r => r.some(cell => cell.trim() !== ''));
|
|
56
|
+
if (!header) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return dataRows.map(
|
|
61
|
+
dataRow =>
|
|
62
|
+
header.reduce((acc, key, idx) => {
|
|
63
|
+
acc[key.trim()] = (dataRow[idx] ?? '').trim();
|
|
64
|
+
return acc;
|
|
65
|
+
}, {} as Record<string, string>) as T,
|
|
66
|
+
);
|
|
67
|
+
}
|