Add admin feature, extended SUVs and correct age 7 vehicles.
This commit is contained in:
@@ -37,27 +37,60 @@ ipcMain.on(ipcTypes.default.audit.toMain.runAudit, async (event, { sheetName })
|
||||
const detailSheet = obj.find((sheet) => sheet.name === sheetName);
|
||||
const claimsArray = [];
|
||||
let foundHeaderRow, foundTotalRow;
|
||||
|
||||
let clmIndex,
|
||||
close_dateIndex,
|
||||
v_model_yrIndex,
|
||||
v_makedescIndex,
|
||||
v_modelIndex,
|
||||
under20kmilesIndex,
|
||||
pan_totalIndex,
|
||||
paa_totalIndex,
|
||||
pal_totalIndex,
|
||||
pam_totalIndex,
|
||||
eligible_db_price_totalIndex,
|
||||
eligible_act_price_totalIndex,
|
||||
expected_rps_dollarsIndex,
|
||||
actual_rps_dollarsIndex;
|
||||
|
||||
detailSheet.data.forEach((line) => {
|
||||
//Check the first element. If it's claim number, we have our header row. the next one is important.
|
||||
if (!foundHeaderRow && line[0] === "Claim Number") {
|
||||
foundHeaderRow = true;
|
||||
//Set all of the indexes to match the titles.
|
||||
|
||||
clmIndex = line.findIndex((l) => l === "Claim Number");
|
||||
close_dateIndex = line.findIndex((l) => l === "Ready for Pay Date");
|
||||
v_model_yrIndex = line.findIndex((l) => l === "Vehicle Year");
|
||||
v_makedescIndex = line.findIndex((l) => l === "Vehicle Make");
|
||||
v_modelIndex = line.findIndex((l) => l === "Vehicle Model");
|
||||
under20kmilesIndex = line.findIndex((l) => l === "Under 20K");
|
||||
pan_totalIndex = line.findIndex((l) => l === "OE Part Prices");
|
||||
paa_totalIndex = line.findIndex((l) => l === "AM Part Prices");
|
||||
pal_totalIndex = line.findIndex((l) => l === "Recycled Part Prices");
|
||||
pam_totalIndex = line.findIndex((l) => l === "Reman & Other Part Prices");
|
||||
eligible_db_price_totalIndex = line.findIndex((l) => l === "(a) Eligible OEM Part Prices");
|
||||
eligible_act_price_totalIndex = line.findIndex((l) => l === "(b) Eligible Actual Part Prices");
|
||||
expected_rps_dollarsIndex = line.findIndex((l) => l === "(e) Expected RPS $ ");
|
||||
actual_rps_dollarsIndex = line.findIndex((l) => l === "(f) Actual RPS $");
|
||||
} else if (foundHeaderRow && !foundTotalRow && line[0] && line[0] !== "Grand Total") {
|
||||
//Add it to the array
|
||||
|
||||
const row = {
|
||||
clm_no: line[0].startsWith("00") ? line[0].slice(2) : line[0],
|
||||
close_date: line[1],
|
||||
v_model_yr: line[3],
|
||||
v_makedesc: line[4],
|
||||
v_model: line[5],
|
||||
under20kmiles: line[6],
|
||||
pan_total: line[7],
|
||||
paa_total: line[8],
|
||||
pal_total: line[9],
|
||||
pam_total: line[10],
|
||||
eligible_db_price_total: Math.round((line[11] + Number.EPSILON) * 100) / 100,
|
||||
eligible_act_price_total: Math.round((line[12] + Number.EPSILON) * 100) / 100,
|
||||
expected_rps_dollars: Math.round((line[15] + Number.EPSILON) * 100) / 100,
|
||||
actual_rps_dollars: Math.round((line[16] + Number.EPSILON) * 100) / 100
|
||||
clm_no: line[clmIndex].startsWith("00") ? line[clmIndex].slice(2) : line[clmIndex],
|
||||
close_date: line[close_dateIndex],
|
||||
v_model_yr: line[v_model_yrIndex],
|
||||
v_makedesc: line[v_makedescIndex],
|
||||
v_model: line[v_modelIndex],
|
||||
under20kmiles: line[under20kmilesIndex],
|
||||
pan_total: line[pan_totalIndex],
|
||||
paa_total: line[paa_totalIndex],
|
||||
pal_total: line[pal_totalIndex],
|
||||
pam_total: line[pam_totalIndex],
|
||||
eligible_db_price_total: Math.round((line[eligible_db_price_totalIndex] + Number.EPSILON) * 100) / 100,
|
||||
eligible_act_price_total: Math.round((line[eligible_act_price_totalIndex] + Number.EPSILON) * 100) / 100,
|
||||
expected_rps_dollars: Math.round((line[expected_rps_dollarsIndex] + Number.EPSILON) * 100) / 100,
|
||||
actual_rps_dollars: Math.round((line[actual_rps_dollarsIndex] + Number.EPSILON) * 100) / 100
|
||||
};
|
||||
claimsArray.push(row);
|
||||
} else {
|
||||
|
||||
@@ -183,5 +183,10 @@
|
||||
"title": "Release Notes for 1.3.4",
|
||||
"date": "10/11/2024",
|
||||
"notes": "Bug Fix\n*Fix typos on application labels."
|
||||
},
|
||||
"1.3.5": {
|
||||
"title": "Release Notes for 1.3.5",
|
||||
"date": "TBD",
|
||||
"notes": "Bug Fix\n*Fix typos on application labels."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"productName": "ImEX RPS",
|
||||
"author": "ImEX Systems Inc. <support@thinkimex.com>",
|
||||
"description": "ImEX RPS",
|
||||
"version": "1.3.4",
|
||||
"version": "1.3.5-alpha.1",
|
||||
"main": "electron/main.js",
|
||||
"homepage": "./",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { WarningOutlined } from "@ant-design/icons";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { DatePicker, message, notification, Spin } from "antd";
|
||||
import dayjs from '../../../util/day.js';
|
||||
import { DatePicker, message, notification, Space, Spin } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { UPDATE_JOB } from "../../../graphql/jobs.queries";
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
import { CalculateVehicleAge } from "../../../ipc/ipc-estimate-utils";
|
||||
import { ChangeOfRuleSet, DateFormat } from "../../../util/constants";
|
||||
import dayjs from "../../../util/day.js";
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
export default function CloseDateDisplayMolecule({ job, jobId, close_date }) {
|
||||
@@ -16,19 +16,19 @@ export default function CloseDateDisplayMolecule({ job, jobId, close_date }) {
|
||||
|
||||
const handleChange = async (newDate) => {
|
||||
ipcRenderer.send(ipcTypes.app.toMain.track, {
|
||||
event: "SET_CLOSED_DATE",
|
||||
event: "SET_CLOSED_DATE"
|
||||
});
|
||||
setLoading(true);
|
||||
setValue(newDate);
|
||||
const requires_reimport = ChangeOfRuleSet({
|
||||
prevDateMoment: job.close_date ? dayjs(job.close_date) : dayjs(job.created_at),
|
||||
newDateMoment: newDate ? newDate : dayjs(),
|
||||
newDateMoment: newDate ? newDate : dayjs()
|
||||
});
|
||||
if (requires_reimport) {
|
||||
notification.open({
|
||||
type: "warning",
|
||||
message:
|
||||
"Changing the R4P date has changed the applicable ruleset. Please re-import the job for accurate scoring.",
|
||||
"Changing the R4P date has changed the applicable ruleset. Please re-import the job for accurate scoring."
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ export default function CloseDateDisplayMolecule({ job, jobId, close_date }) {
|
||||
job: {
|
||||
close_date: newDate,
|
||||
v_age: CalculateVehicleAge({ ...job, close_date: newDate }),
|
||||
requires_reimport: job.requires_reimport || requires_reimport,
|
||||
},
|
||||
},
|
||||
requires_reimport: job.requires_reimport || requires_reimport
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!result.errors) {
|
||||
@@ -53,17 +53,13 @@ export default function CloseDateDisplayMolecule({ job, jobId, close_date }) {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<DatePicker
|
||||
value={value && value.isValid() ? value : null}
|
||||
onChange={handleChange}
|
||||
format={DateFormat}
|
||||
/>
|
||||
<DatePicker value={value && value.isValid() ? value : null} onChange={handleChange} format={DateFormat} />
|
||||
{loading && <Spin size="small" />}
|
||||
{value && !value.isValid() && (
|
||||
<div>
|
||||
<Space size="small">
|
||||
<WarningOutlined className="blink_me" style={{ color: "tomato" }} />
|
||||
<span>No date set.</span>
|
||||
<WarningOutlined style={{ marginLeft: ".5rem", color: "orange" }} />
|
||||
</div>
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import TimeAgoFormatter from "../../atoms/time-ago-formatter/time-ago-formatter.
|
||||
import VehicleGroupAlertAtom from "../../atoms/vehicle-group-alert/vehicle-group-alert.atom";
|
||||
import CloseDateDisplayMolecule from "../close-date-display/close-date-display.molecule";
|
||||
import JobGroupMolecule from "../job-group/job-group.molecule";
|
||||
import moment from "moment";
|
||||
|
||||
export default function JobsDetailDescriptionMolecule({ loading, job }) {
|
||||
const hasQuantityGreaterThan1 = useMemo(() => {
|
||||
@@ -67,7 +68,9 @@ export default function JobsDetailDescriptionMolecule({ loading, job }) {
|
||||
<CloseDateDisplayMolecule job={job} jobId={job.id} close_date={job.close_date} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Last Updated">
|
||||
<TimeAgoFormatter>{job.updated_at}</TimeAgoFormatter>
|
||||
<Tooltip title={`First Created ${moment(job.created_at).format("MM/DD/YY")}`}>
|
||||
<TimeAgoFormatter>{job.updated_at}</TimeAgoFormatter>
|
||||
</Tooltip>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="# RPS Eligible Parts">
|
||||
{job && job.joblines.filter((i) => !i.ignore && i.db_ref !== "900511").length}
|
||||
|
||||
@@ -47,7 +47,8 @@ export function JobsListItemMolecule({ selectedJobId, setSelectedJobId, item, re
|
||||
{!item.close_date && (
|
||||
<WarningOutlined
|
||||
title="No Ready for Payment Date has been set for this job."
|
||||
style={{ marginLeft: ".5rem", color: "orange" }}
|
||||
className="blink_me"
|
||||
style={{ marginLeft: ".5rem", color: "tomato" }}
|
||||
/>
|
||||
)}
|
||||
{item.requires_reimport && (
|
||||
|
||||
@@ -5,7 +5,8 @@ import {
|
||||
FileAddFilled,
|
||||
LogoutOutlined,
|
||||
PieChartOutlined,
|
||||
SettingFilled
|
||||
SettingFilled,
|
||||
AlertOutlined
|
||||
} from "@ant-design/icons";
|
||||
import { Menu } from "antd";
|
||||
import React from "react";
|
||||
@@ -66,7 +67,17 @@ export default function SiderMenuOrganism() {
|
||||
Quit
|
||||
</span>
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
// ...(process.env.NODE_ENV !== "production"
|
||||
// ? [
|
||||
// {
|
||||
// key: "/admin",
|
||||
// icon: <AlertOutlined />,
|
||||
// label: <Link to="/admin">ADMIN</Link>
|
||||
// }
|
||||
// ]
|
||||
// : [])
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
143
src/components/pages/admin/admin.page.jsx
Normal file
143
src/components/pages/admin/admin.page.jsx
Normal file
@@ -0,0 +1,143 @@
|
||||
import { ApolloClient, gql, InMemoryCache, useApolloClient } from "@apollo/client";
|
||||
import { HttpLink } from "@apollo/client/link/http"; //"apollo-link-http";
|
||||
import { Button, Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { LOCAL_DOESNOTUpsertEstimate } from "../../../ipc/ipc-estimate-utils";
|
||||
import _ from "lodash";
|
||||
import moment from "moment/moment";
|
||||
import { dateSort } from "../../../util/sorters";
|
||||
|
||||
const httpLink = new HttpLink({
|
||||
uri: import.meta.env.VITE_APP_GRAPHQL_ENDPOINT,
|
||||
headers: {
|
||||
"x-hasura-admin-secret": `ImEXRPSDataBase`
|
||||
}
|
||||
});
|
||||
|
||||
const localCLient = new ApolloClient({ link: httpLink, cache: new InMemoryCache({}) });
|
||||
export default function AdminPage() {
|
||||
const client = useApolloClient();
|
||||
const clientToUse = client;
|
||||
|
||||
const [wrongGroups, setWrongGroups] = useState([]);
|
||||
|
||||
const handleQuery = async () => {
|
||||
//TODO: MAKE SURE THIS USES THE ADMIN SECRET INSTEAD.
|
||||
const {
|
||||
data: { jobs }
|
||||
} = await clientToUse.query({
|
||||
variables: { createdAt: "2024-01-01" },
|
||||
query: gql`
|
||||
query ADMIN_GET_JOBS($createdAt: timestamptz) {
|
||||
jobs(
|
||||
where: {
|
||||
_and: [
|
||||
{ created_at: { _gte: $createdAt } }
|
||||
{ _or: [{ close_date: { _is_null: true } }, { close_date: { _gte: "2024-09-01" } }] }
|
||||
]
|
||||
}
|
||||
) {
|
||||
ownr_ln
|
||||
ownr_fn
|
||||
ins_co_nm
|
||||
group
|
||||
group_verified
|
||||
clm_total
|
||||
clm_no
|
||||
close_date
|
||||
id
|
||||
loss_date
|
||||
updated_at
|
||||
created_at
|
||||
v_age
|
||||
v_makedesc
|
||||
v_model
|
||||
v_model_yr
|
||||
v_vin
|
||||
v_type
|
||||
requires_reimport
|
||||
v_mileage
|
||||
joblines {
|
||||
act_price
|
||||
db_price
|
||||
part_qty
|
||||
part_type
|
||||
price_diff
|
||||
price_diff_pc
|
||||
updated_at
|
||||
oem_partno
|
||||
line_no
|
||||
line_ind
|
||||
line_desc
|
||||
ignore
|
||||
id
|
||||
db_ref
|
||||
unq_seq
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
});
|
||||
|
||||
const NoDateSetJobs = jobs.filter((j) => !j.close_date);
|
||||
|
||||
//For the jobs that DO have a date, let's see their group.
|
||||
const JobsInWrongGroup = [];
|
||||
const AllJobResults = [];
|
||||
for (const job of jobs.filter((j) => true || j.close_date)) {
|
||||
const initialJob = { ...job };
|
||||
|
||||
const calcedGroup = await LOCAL_DOESNOTUpsertEstimate(initialJob);
|
||||
console.log("🚀 ~ handleQuery ~ calcedGroup:", calcedGroup);
|
||||
AllJobResults.push({
|
||||
close_date: job.close_date,
|
||||
make: initialJob.v_makedesc,
|
||||
model: initialJob.v_model,
|
||||
type: initialJob.v_type,
|
||||
calced_v_type: calcedGroup.v_type,
|
||||
job_group: initialJob.group,
|
||||
calced_group: calcedGroup.group
|
||||
});
|
||||
if (initialJob.group !== calcedGroup.group) {
|
||||
JobsInWrongGroup.push({ ...job, calced_group: calcedGroup.group, calced_v_type: calcedGroup.v_type });
|
||||
}
|
||||
// break;
|
||||
}
|
||||
|
||||
console.table(AllJobResults);
|
||||
console.log(`Found ${JobsInWrongGroup.length} jobs that are in the wrong group.`);
|
||||
console.table(JobsInWrongGroup.map((j) => _.pick(j, ["v_makedesc", "v_model", "group", "calced_group"])));
|
||||
setWrongGroups(JobsInWrongGroup);
|
||||
const jobsToMarkForReimport = [...NoDateSetJobs, ...JobsInWrongGroup];
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ height: "100%" }}>
|
||||
<Button onClick={handleQuery}>Run the query</Button>
|
||||
<Table
|
||||
title={() => "Jobs with the wrong group set."}
|
||||
dataSource={wrongGroups}
|
||||
columns={[
|
||||
{
|
||||
key: "created_at",
|
||||
dataIndex: "created_at",
|
||||
title: "Created",
|
||||
sorter: (a, b) => dateSort(a.created_at, b.created_at),
|
||||
render: (record) => moment(record).format("YYYY-MM-DD")
|
||||
},
|
||||
{ key: "close_date", dataIndex: "close_date", title: "Close Date" },
|
||||
{ key: "clm_no", dataIndex: "clm_no", title: "Claim" },
|
||||
{ key: "v_makedesc", dataIndex: "v_makedesc", title: "Make" },
|
||||
{ key: "v_model", dataIndex: "v_model", title: "Model" },
|
||||
{ key: "v_age", dataIndex: "v_age", title: "Age" },
|
||||
{ key: "v_type", dataIndex: "v_type", title: "Type" },
|
||||
{ key: "calced_v_type", dataIndex: "calced_v_type", title: "CALCED Type" },
|
||||
{ key: "group", dataIndex: "group", title: "Group" },
|
||||
{ key: "calced_group", dataIndex: "calced_group", title: "CALCED Group" }
|
||||
]}
|
||||
pagination={{ pageSize: 20 }}
|
||||
rowKey={"id"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import ReportingPage from "../reporting/reporting.page";
|
||||
import ScanPage from "../scan/scan.page";
|
||||
import SettingsPage from "../settings/settings.page";
|
||||
import AuditPage from "../audit/audit.page";
|
||||
import AdminPage from "../admin/admin.page";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop });
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
@@ -41,6 +42,7 @@ export function RoutesPage({ bodyshop }) {
|
||||
<Route exact path="/reporting" element={<ReportingPage />} />
|
||||
<Route exact path="/audit" element={<AuditPage />} />
|
||||
<Route exact path="/scan" element={<ScanPage />} />
|
||||
<Route exact path="/admin" element={<AdminPage />} />
|
||||
<Route exact path="/" element={<JobsPage />} />
|
||||
</Routes>
|
||||
</Layout.Content>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,5 +27,7 @@
|
||||
"VENTURE",
|
||||
"SAFARI",
|
||||
"VANAGON",
|
||||
"WINDSTAR"
|
||||
"WINDSTAR",
|
||||
"TOWN&COUNTRY",
|
||||
"ROUTAN"
|
||||
]
|
||||
|
||||
@@ -289,6 +289,7 @@
|
||||
"CAYENNE",
|
||||
"XC90 PLUG-IN",
|
||||
"MODEL X",
|
||||
"MODEL Y",
|
||||
"GLC300",
|
||||
"SANTA FE HYBRID",
|
||||
"G63",
|
||||
@@ -358,5 +359,133 @@
|
||||
"CX-70",
|
||||
"SANTA FE XL",
|
||||
"RENEGADE",
|
||||
"QX50"
|
||||
"QX50",
|
||||
"ECLIPSE CROSS",
|
||||
"QX80",
|
||||
"X5",
|
||||
"X3",
|
||||
"X1",
|
||||
"X4",
|
||||
"ENCLAVE",
|
||||
"ENCORE GX",
|
||||
"CAYENNE HYBRID",
|
||||
"SOUL",
|
||||
"GX 460",
|
||||
"UX 250H",
|
||||
"XT5",
|
||||
"GLE53",
|
||||
"XT4",
|
||||
"SQ7",
|
||||
"NX 350H",
|
||||
"GLK350",
|
||||
"GLE350",
|
||||
"NX 300H",
|
||||
"NX 200T",
|
||||
"RANGE ROVER EVOQUE",
|
||||
"GLS450",
|
||||
"TERRAIN DENALI",
|
||||
"GRAND CHEROKEE L",
|
||||
"GLE400",
|
||||
"TUCSON PLUG-IN",
|
||||
"BLAZER",
|
||||
"ASCENT",
|
||||
"HIGHLANDER HYBRID",
|
||||
"ATLAS CROSS SPORT",
|
||||
"XC40",
|
||||
"VENZA HYBRID",
|
||||
"GLA45",
|
||||
"GLB250",
|
||||
"GRAND HIGHLANDER",
|
||||
"GV70",
|
||||
"NIRO",
|
||||
"NIRO EV",
|
||||
"GLA250",
|
||||
"ESCAPE PLUG-IN",
|
||||
"WAGONEER",
|
||||
"CX-30",
|
||||
"QX60",
|
||||
"GRAND CHEROKEE 4XE",
|
||||
"SPORTAGE HYBRID",
|
||||
"EV6",
|
||||
"TONALE PLUG-IN",
|
||||
"GLC43 COUPE",
|
||||
"X2",
|
||||
"RX 350L",
|
||||
"HORNET",
|
||||
"ENVISTA",
|
||||
"LEVANTE S",
|
||||
"SPORTAGE PLUG-IN",
|
||||
"ORLANDO",
|
||||
"X5 M",
|
||||
"EXPLORER HYBRID",
|
||||
"FREESTYLE",
|
||||
"CORSAIR",
|
||||
"K1500 YUKON XL",
|
||||
"RANGE ROVER",
|
||||
"SUV W/O LABOR",
|
||||
"ID.4",
|
||||
"CX-90",
|
||||
"X7",
|
||||
"CORSAIR PLUG-IN",
|
||||
"ESCALADE EXT",
|
||||
"QX55",
|
||||
"DISCOVERY",
|
||||
"BOLT EUV",
|
||||
"C40 ELECTRIC",
|
||||
"LR4",
|
||||
"GRAND WAGONEER",
|
||||
"XC60 PLUG-IN",
|
||||
"LR2",
|
||||
"EQE350 SUV",
|
||||
"COROLLA CROSS HYBRID",
|
||||
"SOUL EV",
|
||||
"GRECALE",
|
||||
"SUV W/O LABOR",
|
||||
"QX30",
|
||||
"SQ5",
|
||||
"NIRO PLUG-IN",
|
||||
"BORREGO",
|
||||
"CX-90 PLUG-IN",
|
||||
"XL-7",
|
||||
"SUV W/O LABOR",
|
||||
"SUV W/O LABOR",
|
||||
"I-PACE",
|
||||
"HORNET PLUG-IN",
|
||||
"UX 300H",
|
||||
"ML320 CDI",
|
||||
"VERACRUZ",
|
||||
"SQ8",
|
||||
"GLE53 COUPE",
|
||||
"ZDX",
|
||||
"9-7X",
|
||||
"ARIYA",
|
||||
"ASPEN",
|
||||
"AVIATOR PLUG-IN",
|
||||
"B9 TRIBECA",
|
||||
"BRAVADA",
|
||||
"ENVOY XL",
|
||||
"EQB350",
|
||||
"EQB350 SUV",
|
||||
"ESCALADE-V",
|
||||
"E-TRON",
|
||||
"FX37",
|
||||
"GL320 CDI",
|
||||
"GLADIATOR",
|
||||
"GLC43",
|
||||
"GLE450 COUPE",
|
||||
"GLE63",
|
||||
"GV60",
|
||||
"MKT TOWN CAR",
|
||||
"ML350",
|
||||
"ML550",
|
||||
"ML63",
|
||||
"NX 250",
|
||||
"Q4 E-TRON",
|
||||
"Q8 E-TRON SPORTBACK",
|
||||
"QX4",
|
||||
"QX56",
|
||||
"SANTA FE PLUG-IN",
|
||||
"UX 200",
|
||||
"WAGONEER L",
|
||||
"XB"
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user