@bisondesk/core-sdk 1.0.442 → 1.0.444

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.
@@ -0,0 +1,78 @@
1
+ import { OpportunityType } from '../constants.js';
2
+ import { VehicleSaleDealStatus, VehicleSaleLogisticsStatus } from './opportunities.js';
3
+ import { VehiclePurchaseDealStatus, VehiclePurchaseLogisticsStatus } from './vehicles.js';
4
+ export type VehicleSaleOverview = {
5
+ opportunityId: string;
6
+ type: OpportunityType;
7
+ userId: string;
8
+ clientId: string;
9
+ clientCode: number;
10
+ clientCountryCode: string;
11
+ clientVat?: string;
12
+ conglomerate?: boolean;
13
+ clientEmail?: string;
14
+ clientPhone?: string;
15
+ dealStatus: VehicleSaleDealStatus;
16
+ logisticsStatus: VehicleSaleLogisticsStatus;
17
+ createdAt: string;
18
+ engagedAt?: string;
19
+ acceptedAt?: string;
20
+ validatedAt?: string;
21
+ reviewedAt?: string;
22
+ preparedAt?: string;
23
+ deliveredAt?: string;
24
+ wonAt?: string;
25
+ saleAt?: string;
26
+ firstInvoiceIssuedAt?: string;
27
+ lastInvoiceIssuedAt?: string;
28
+ firstPaymentAt?: string;
29
+ fullPaymentAt?: string;
30
+ expectedAmount: string;
31
+ actualAmount: string;
32
+ lifetimeActualAmount: string;
33
+ hasMainInvoice?: boolean;
34
+ };
35
+ export type VehiclePurchaseOverview = {
36
+ userId: string;
37
+ dealStatus: VehiclePurchaseDealStatus;
38
+ logisticsStatus: VehiclePurchaseLogisticsStatus;
39
+ supplierId: string;
40
+ supplierCode: string;
41
+ supplierCountryCode: string;
42
+ supplierVat?: string;
43
+ conglomerate?: boolean;
44
+ supplierEmail?: string;
45
+ supplierPhone?: string;
46
+ firstInvoiceIssuedAt?: string;
47
+ lastInvoiceIssuedAt?: string;
48
+ firstPaymentAt?: string;
49
+ fullPaymentAt?: string;
50
+ expectedAmount: string;
51
+ actualAmount: string;
52
+ purchaseAt?: string;
53
+ marketingAt?: string;
54
+ evaluationAt?: string;
55
+ purchaseAgreedAt?: string;
56
+ arrivedAt?: string;
57
+ checkedInAt?: string;
58
+ hasMainInvoice?: boolean;
59
+ };
60
+ export type VehicleProfitOverview = {
61
+ expectedProfit?: string;
62
+ expectedRoi?: string;
63
+ actualProfit?: string;
64
+ actualRoi?: string;
65
+ };
66
+ type VehicleSummary = {
67
+ branch: string;
68
+ stockNumber: string;
69
+ id: string;
70
+ };
71
+ export type VehicleBusinessOverview = {
72
+ vehicle: VehicleSummary;
73
+ purchase: VehiclePurchaseOverview;
74
+ sale?: VehicleSaleOverview;
75
+ profit?: VehicleProfitOverview;
76
+ };
77
+ export {};
78
+ //# sourceMappingURL=vehicle-performance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vehicle-performance.d.ts","sourceRoot":"/","sources":["types/vehicle-performance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=vehicle-performance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vehicle-performance.js","sourceRoot":"/","sources":["types/vehicle-performance.ts"],"names":[],"mappings":"","sourcesContent":["import { OpportunityType } from '../constants.js';\nimport { VehicleSaleDealStatus, VehicleSaleLogisticsStatus } from './opportunities.js';\nimport { VehiclePurchaseDealStatus, VehiclePurchaseLogisticsStatus } from './vehicles.js';\n\nexport type VehicleSaleOverview = {\n opportunityId: string;\n type: OpportunityType;\n userId: string; // account manager of the latest opportunity (if opportunity is >= review)\n\n // client details\n clientId: string;\n clientCode: number;\n clientCountryCode: string;\n clientVat?: string;\n conglomerate?: boolean;\n clientEmail?: string;\n clientPhone?: string;\n\n // vehicle details\n dealStatus: VehicleSaleDealStatus;\n logisticsStatus: VehicleSaleLogisticsStatus;\n\n // opportunity dates\n createdAt: string;\n engagedAt?: string;\n acceptedAt?: string;\n validatedAt?: string;\n reviewedAt?: string;\n preparedAt?: string;\n deliveredAt?: string;\n wonAt?: string;\n\n saleAt?: string; // this is the date that should be considered for the sale according to TJ (often the same as fullPaymentAt)\n\n // money-related details\n firstInvoiceIssuedAt?: string;\n lastInvoiceIssuedAt?: string;\n firstPaymentAt?: string;\n fullPaymentAt?: string;\n expectedAmount: string; // from quote(s)\n actualAmount: string; // from all invoices\n lifetimeActualAmount: string; // sum of all invoices from all opportunities for this vehicle\n\n // is there an invoice with category related to the purchase of commercial vehicle\n // (we probably need a way to flag those categories since it is also important for the stocklist)\n hasMainInvoice?: boolean;\n};\n\nexport type VehiclePurchaseOverview = {\n userId: string; // purchaser\n\n dealStatus: VehiclePurchaseDealStatus;\n logisticsStatus: VehiclePurchaseLogisticsStatus;\n\n supplierId: string;\n supplierCode: string;\n supplierCountryCode: string;\n supplierVat?: string;\n conglomerate?: boolean;\n supplierEmail?: string;\n supplierPhone?: string;\n\n // money-related details\n firstInvoiceIssuedAt?: string;\n lastInvoiceIssuedAt?: string;\n firstPaymentAt?: string;\n fullPaymentAt?: string;\n expectedAmount: string;\n actualAmount: string;\n\n purchaseAt?: string; // this is the date that should be considered for the purchase according to TJ (often the same as fullPaymentAt)\n\n // log\n marketingAt?: string; // no vehicle in our parking, just digital marketing\n evaluationAt?: string; // in consignation\n purchaseAgreedAt?: string;\n // firstPaymentAllowedAt?: string;\n // firstPaymentSentAt?: string;\n // fullPaymentAllowedAt?: string;\n // fullPaymentSentAt?: string;\n arrivedAt?: string;\n checkedInAt?: string;\n\n hasMainInvoice?: boolean;\n};\n\nexport type VehicleProfitOverview = {\n expectedProfit?: string;\n expectedRoi?: string;\n\n actualProfit?: string;\n actualRoi?: string;\n};\n\ntype VehicleSummary = {\n branch: string;\n stockNumber: string;\n id: string;\n};\n\nexport type VehicleBusinessOverview = {\n vehicle: VehicleSummary;\n purchase: VehiclePurchaseOverview;\n sale?: VehicleSaleOverview;\n profit?: VehicleProfitOverview;\n};\n"]}
@@ -30,7 +30,7 @@ export const extractCustomFeatures = (vehicle) => {
30
30
  };
31
31
  export const getInternalTitle = ({ make, category, modelName, bodywork, modelTypeName, }) => {
32
32
  if (category === Categories.Trailer || category === Categories.SemiTrailer) {
33
- return [make, modelName, bodywork]
33
+ return [make, modelName, modelTypeName, bodywork]
34
34
  .filter((v) => !!v)
35
35
  .map((v) => v.trim())
36
36
  .join(' ')
@@ -1 +1 @@
1
- {"version":3,"file":"vehicles.js","sourceRoot":"/","sources":["utils/vehicles.ts"],"names":[],"mappings":"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","sourcesContent":["import { XError } from '@bisondesk/commons-sdk/errors';\nimport { Categories } from '../constants.js';\nimport { VehicleExternalInfo } from '../types/vehicles.js';\n\nexport const extractCustomFeatures = (vehicle: VehicleExternalInfo): string[] => {\n const features: {\n getValue: (vehicle: VehicleExternalInfo) => any;\n picklistValueId: string;\n }[] = [\n {\n getValue: (vehicle) => vehicle.superstructure?.crane?.present,\n picklistValueId: 'crane',\n },\n {\n getValue: (vehicle) => vehicle.superstructure?.tailgate?.present,\n picklistValueId: 'tailgate',\n },\n { getValue: (vehicle) => vehicle.accessories.adr, picklistValueId: 'adr' },\n {\n getValue: (vehicle) => vehicle.accessories.retarderIntarder,\n picklistValueId: 'retarderIntarder',\n },\n {\n getValue: (vehicle) => vehicle.accessories.hydraulicTipperKit,\n picklistValueId: 'hydraulicTipperKit',\n },\n {\n getValue: (vehicle) => vehicle.accessories.lowDeck,\n picklistValueId: 'lowDeck',\n },\n ];\n\n return features\n .filter((feature) => !!feature.getValue(vehicle))\n .map((feature) => feature.picklistValueId);\n};\n\nexport const getInternalTitle = ({\n make,\n category,\n modelName,\n bodywork,\n modelTypeName,\n}: {\n category: string;\n make?: string;\n modelName?: string;\n modelTypeName?: string;\n bodywork?: string;\n}): string => {\n if (category === Categories.Trailer || category === Categories.SemiTrailer) {\n return [make, modelName, bodywork]\n .filter((v): v is string => !!v)\n .map((v) => v.trim())\n .join(' ')\n .trim();\n }\n\n return [make, modelName, modelTypeName]\n .filter((v): v is string => !!v)\n .map((v) => v.trim())\n .join(' ')\n .trim();\n};\n\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n\n// example: 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB, 52 -> AZ, 53 -> BA, 54 -> BB, 702 -> ZZ\nexport const convertNumberToLetters = (num: number): string => {\n const lettersLength = ALPHABET.length;\n\n if (num < 1) {\n return '';\n }\n\n let remainder = num % lettersLength;\n let quotient = Math.floor(num / lettersLength);\n\n // If remainder is 0, it means we should map it to 'Z' and reduce the quotient by 1\n if (remainder === 0) {\n remainder = lettersLength;\n quotient -= 1;\n }\n\n return convertNumberToLetters(quotient) + ALPHABET.charAt(remainder - 1);\n};\n\n// example: A -> 1, B -> 2, Z -> 26, AA -> 27, AB -> 28, AZ -> 52, BA -> 53, BB -> 54, ZZ -> 702\nexport const convertLettersToNumber = (letters: string): number => {\n const base = ALPHABET.length;\n\n let result = 0;\n\n for (let i = 0; i < letters.length; i++) {\n const charValue = ALPHABET.indexOf(letters[i]) + 1;\n result = result * base + charValue;\n }\n\n return result;\n};\n\nexport const getNextRelatedStockNumber = (stockNumber: string): string => {\n const counterPattern = /^([A-Z]+\\d{5})([A-Z]{0,2})$/;\n const match = stockNumber.match(counterPattern);\n if (match == null) {\n throw new XError('core-sdk.vehicles.bad-stock-number', { stockNumber });\n }\n\n const baseStockNumber = match[1];\n const counterLetters = match[2];\n const counterNumber = convertLettersToNumber(counterLetters);\n const nextCounterNumber = counterNumber + 1;\n const nextCounterLetters = convertNumberToLetters(nextCounterNumber);\n return `${baseStockNumber}${nextCounterLetters}`;\n};\n"]}
1
+ {"version":3,"file":"vehicles.js","sourceRoot":"/","sources":["utils/vehicles.ts"],"names":[],"mappings":"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","sourcesContent":["import { XError } from '@bisondesk/commons-sdk/errors';\nimport { Categories } from '../constants.js';\nimport { VehicleExternalInfo } from '../types/vehicles.js';\n\nexport const extractCustomFeatures = (vehicle: VehicleExternalInfo): string[] => {\n const features: {\n getValue: (vehicle: VehicleExternalInfo) => any;\n picklistValueId: string;\n }[] = [\n {\n getValue: (vehicle) => vehicle.superstructure?.crane?.present,\n picklistValueId: 'crane',\n },\n {\n getValue: (vehicle) => vehicle.superstructure?.tailgate?.present,\n picklistValueId: 'tailgate',\n },\n { getValue: (vehicle) => vehicle.accessories.adr, picklistValueId: 'adr' },\n {\n getValue: (vehicle) => vehicle.accessories.retarderIntarder,\n picklistValueId: 'retarderIntarder',\n },\n {\n getValue: (vehicle) => vehicle.accessories.hydraulicTipperKit,\n picklistValueId: 'hydraulicTipperKit',\n },\n {\n getValue: (vehicle) => vehicle.accessories.lowDeck,\n picklistValueId: 'lowDeck',\n },\n ];\n\n return features\n .filter((feature) => !!feature.getValue(vehicle))\n .map((feature) => feature.picklistValueId);\n};\n\nexport const getInternalTitle = ({\n make,\n category,\n modelName,\n bodywork,\n modelTypeName,\n}: {\n category: string;\n make?: string;\n modelName?: string;\n modelTypeName?: string;\n bodywork?: string;\n}): string => {\n if (category === Categories.Trailer || category === Categories.SemiTrailer) {\n return [make, modelName, modelTypeName, bodywork]\n .filter((v): v is string => !!v)\n .map((v) => v.trim())\n .join(' ')\n .trim();\n }\n\n return [make, modelName, modelTypeName]\n .filter((v): v is string => !!v)\n .map((v) => v.trim())\n .join(' ')\n .trim();\n};\n\nconst ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n\n// example: 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB, 52 -> AZ, 53 -> BA, 54 -> BB, 702 -> ZZ\nexport const convertNumberToLetters = (num: number): string => {\n const lettersLength = ALPHABET.length;\n\n if (num < 1) {\n return '';\n }\n\n let remainder = num % lettersLength;\n let quotient = Math.floor(num / lettersLength);\n\n // If remainder is 0, it means we should map it to 'Z' and reduce the quotient by 1\n if (remainder === 0) {\n remainder = lettersLength;\n quotient -= 1;\n }\n\n return convertNumberToLetters(quotient) + ALPHABET.charAt(remainder - 1);\n};\n\n// example: A -> 1, B -> 2, Z -> 26, AA -> 27, AB -> 28, AZ -> 52, BA -> 53, BB -> 54, ZZ -> 702\nexport const convertLettersToNumber = (letters: string): number => {\n const base = ALPHABET.length;\n\n let result = 0;\n\n for (let i = 0; i < letters.length; i++) {\n const charValue = ALPHABET.indexOf(letters[i]) + 1;\n result = result * base + charValue;\n }\n\n return result;\n};\n\nexport const getNextRelatedStockNumber = (stockNumber: string): string => {\n const counterPattern = /^([A-Z]+\\d{5})([A-Z]{0,2})$/;\n const match = stockNumber.match(counterPattern);\n if (match == null) {\n throw new XError('core-sdk.vehicles.bad-stock-number', { stockNumber });\n }\n\n const baseStockNumber = match[1];\n const counterLetters = match[2];\n const counterNumber = convertLettersToNumber(counterLetters);\n const nextCounterNumber = counterNumber + 1;\n const nextCounterLetters = convertNumberToLetters(nextCounterNumber);\n return `${baseStockNumber}${nextCounterLetters}`;\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bisondesk/core-sdk",
3
- "version": "1.0.442",
3
+ "version": "1.0.444",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -10,6 +10,26 @@ import { LeasingQuoteParams } from '../types/quote-settings.js';
10
10
  import { Quote } from '../types/quotes.js';
11
11
  import { OpportunityReservation } from '../types/reservations.js';
12
12
 
13
+ export const listOpportunities = async (
14
+ tenantId: string,
15
+ filterOptions?: {}
16
+ ): Promise<Opportunity[]> => {
17
+ const auth = await getAdminAuth();
18
+ const result = await fetchJson<Opportunity[]>(
19
+ `${process.env.CORE_API_ORIGIN}/api/opportunities/list`,
20
+ {
21
+ method: 'POST',
22
+ headers: cleanHeaders({
23
+ Authorization: auth,
24
+ [TENANT_ID_ADMIN_HEADER]: tenantId,
25
+ }),
26
+ body: JSON.stringify(filterOptions),
27
+ }
28
+ );
29
+
30
+ return result ?? [];
31
+ };
32
+
13
33
  export const getOpportunityById = async (
14
34
  tenantId: string,
15
35
  opportunityId: string
@@ -120,7 +120,7 @@ export const listVehiclesMarketing = async (
120
120
  });
121
121
 
122
122
  if (response.ok) {
123
- return response.status === 200 ? (response.json() as any) : undefined;
123
+ return response.status === 200 ? (response.json() as any) : [];
124
124
  }
125
125
 
126
126
  const body = await response.text();
@@ -10,6 +10,19 @@ import { BaseSearchRequest } from './search.js';
10
10
  import { DataRecord, ReferenceData } from './utils.js';
11
11
  import { Vehicle } from './vehicles.js';
12
12
 
13
+ export type ListOpportunitiesFilters = {
14
+ offset?: number;
15
+ limit?: number;
16
+ organizationId?: string;
17
+ contactId?: string;
18
+ vehicleId?: string;
19
+ excludeOpportunityId?: string;
20
+ excludeLost?: boolean;
21
+ statuses?: OpportunityStatus[];
22
+ since?: string;
23
+ until?: string;
24
+ };
25
+
13
26
  export enum OpportunityActions {
14
27
  ADD_COMMISSION = 'add_commission',
15
28
  CREATE_QUOTE = 'create_quote',
@@ -362,7 +375,6 @@ export type LeasingQuoteTemplateData = {
362
375
  leasing: {
363
376
  deposit: string;
364
377
  totalMonthlyAmount: string;
365
- totalMonthlyAmountExclVat: string;
366
378
  depositExclVat: string;
367
379
  startupFee: string;
368
380
  startupFeeExclVat: string;
@@ -433,7 +445,7 @@ export type LeasingProformaTemplateData = {
433
445
  };
434
446
  };
435
447
 
436
- export type SalesProformaTemplateData = {
448
+ export type SalesTemplateData = {
437
449
  opportunity: {
438
450
  id: string;
439
451
  offerNumber: string;
@@ -456,6 +468,7 @@ export type SalesProformaTemplateData = {
456
468
  type?: string;
457
469
  km: string | number;
458
470
  vin: string;
471
+ year: string;
459
472
  };
460
473
  c: {
461
474
  organizationId?: string;
@@ -468,41 +481,7 @@ export type SalesProformaTemplateData = {
468
481
  address?: string;
469
482
  country: string;
470
483
  };
471
- i: LineItemPdfTemplate[];
472
- t: {
473
- totalExclVat: string;
474
- vatAmount: string;
475
- total: string;
476
- };
477
- };
478
-
479
- export type SalesAgreementTemplateData = {
480
- opportunity: {
481
- id: string;
482
- offerNumber: string;
483
- };
484
- currentDate: string;
485
- accountManager: {
486
- fullName: string;
487
- email: string;
488
- phone: string;
489
- };
490
- vehicle: {
491
- line1: string;
492
- line2: string;
493
- stockNumber: string;
494
- };
495
- c: {
496
- organizationId?: string;
497
- clientId: string;
498
- company: string;
499
- fullName: string;
500
- vatNumber?: string;
501
- email?: string;
502
- phone?: string;
503
- address?: string;
504
- country: string;
505
- };
484
+ iExtended: LineItemPdfTemplate[];
506
485
  i: LineItemPdfTemplate[];
507
486
  t: {
508
487
  totalExclVat: string;
@@ -0,0 +1,103 @@
1
+ // The commission can be expressed either as a percentage (for profit-based metrics)
2
+ // or as an amount per unit (for unit-based metrics).
3
+ export type CommissionType = 'percentage' | 'unit';
4
+
5
+ // Comprehensive metric configuration
6
+ export type MetricConfig = {
7
+ id: string;
8
+ commissionType: CommissionType;
9
+ format?: Intl.NumberFormatOptions;
10
+ };
11
+
12
+ // A tier defines a range of performance (using lower and optional upper bounds)
13
+ // along with the associated commission rate. For example, 0–100 units, then 100–400 units, etc.
14
+ export type CommissionTier = {
15
+ lowerBound: number; // inclusive
16
+ upperBound?: number; // inclusive (omit for the last tier)
17
+ commissionRate: number;
18
+ default?: boolean; // if true, this tier's upper bound is used as reference for dashboards visualizations
19
+ };
20
+
21
+ // Each target (metric) has one or more tiers.
22
+ // For example, for UnitsSold you might have three tiers corresponding to bare minimum, normal, and above average.
23
+ export type TargetCommission = {
24
+ metricId: string;
25
+ tiers: CommissionTier[];
26
+ };
27
+
28
+ export type UserCommissionPlan = {
29
+ userId: string;
30
+ year: number;
31
+ targets: TargetCommission[];
32
+ };
33
+
34
+ export enum CommissionGrade {
35
+ TooLow = 'tooLow',
36
+ Low = 'low',
37
+ OnTarget = 'onTarget',
38
+ }
39
+
40
+ export type UserCommissionStatus = {
41
+ userId: string;
42
+ createdAt: string; // iso date string
43
+ year: number;
44
+ performance: {
45
+ [metricId: string]: {
46
+ value: string; // actual metric achieved
47
+ estimated?: string; // estimated commission for the metric, based on the current trend
48
+ grade?: CommissionGrade; // grade for the metric
49
+ target?: string; // the upper bound of the default tier
50
+ };
51
+ };
52
+ commission: {
53
+ total: string;
54
+ potential?: string;
55
+ estimated?: string; // estimated commission for the year, based on the current trend
56
+ grade?: CommissionGrade;
57
+ detailed?: {
58
+ [metricId: string]: {
59
+ earned: string; // commission amount for each target
60
+ potential?: string; // potential commission for the metric, based on the actual metric achieved and the commission tiers
61
+ };
62
+ };
63
+ };
64
+ payments: {
65
+ total: string;
66
+ yearly?: {
67
+ // details for each year for which the outstanding commission is > 0
68
+ [year: number]: {
69
+ paid: string;
70
+ };
71
+ };
72
+ };
73
+ outstanding: {
74
+ total: string;
75
+ // details for each year for which the outstanding commission is > 0
76
+ yearly?: {
77
+ [year: number]: {
78
+ outstanding: string;
79
+ };
80
+ };
81
+ };
82
+ };
83
+
84
+ export type NewUserCommissionPayment = {
85
+ userId: string; // who was the payment made to
86
+ paidBy: string;
87
+ paidAt: string;
88
+ amount: string;
89
+ };
90
+
91
+ export type UserCommissionPayment = {
92
+ id: string;
93
+ } & NewUserCommissionPayment;
94
+
95
+ export type UserCommissionsPaymentRequest = {
96
+ limit?: number;
97
+ nextToken?: string;
98
+ };
99
+
100
+ export type UserCommissionInfo = {
101
+ manager?: boolean;
102
+ performance: boolean;
103
+ };
@@ -0,0 +1,106 @@
1
+ import { OpportunityType } from '../constants.js';
2
+ import { VehicleSaleDealStatus, VehicleSaleLogisticsStatus } from './opportunities.js';
3
+ import { VehiclePurchaseDealStatus, VehiclePurchaseLogisticsStatus } from './vehicles.js';
4
+
5
+ export type VehicleSaleOverview = {
6
+ opportunityId: string;
7
+ type: OpportunityType;
8
+ userId: string; // account manager of the latest opportunity (if opportunity is >= review)
9
+
10
+ // client details
11
+ clientId: string;
12
+ clientCode: number;
13
+ clientCountryCode: string;
14
+ clientVat?: string;
15
+ conglomerate?: boolean;
16
+ clientEmail?: string;
17
+ clientPhone?: string;
18
+
19
+ // vehicle details
20
+ dealStatus: VehicleSaleDealStatus;
21
+ logisticsStatus: VehicleSaleLogisticsStatus;
22
+
23
+ // opportunity dates
24
+ createdAt: string;
25
+ engagedAt?: string;
26
+ acceptedAt?: string;
27
+ validatedAt?: string;
28
+ reviewedAt?: string;
29
+ preparedAt?: string;
30
+ deliveredAt?: string;
31
+ wonAt?: string;
32
+
33
+ saleAt?: string; // this is the date that should be considered for the sale according to TJ (often the same as fullPaymentAt)
34
+
35
+ // money-related details
36
+ firstInvoiceIssuedAt?: string;
37
+ lastInvoiceIssuedAt?: string;
38
+ firstPaymentAt?: string;
39
+ fullPaymentAt?: string;
40
+ expectedAmount: string; // from quote(s)
41
+ actualAmount: string; // from all invoices
42
+ lifetimeActualAmount: string; // sum of all invoices from all opportunities for this vehicle
43
+
44
+ // is there an invoice with category related to the purchase of commercial vehicle
45
+ // (we probably need a way to flag those categories since it is also important for the stocklist)
46
+ hasMainInvoice?: boolean;
47
+ };
48
+
49
+ export type VehiclePurchaseOverview = {
50
+ userId: string; // purchaser
51
+
52
+ dealStatus: VehiclePurchaseDealStatus;
53
+ logisticsStatus: VehiclePurchaseLogisticsStatus;
54
+
55
+ supplierId: string;
56
+ supplierCode: string;
57
+ supplierCountryCode: string;
58
+ supplierVat?: string;
59
+ conglomerate?: boolean;
60
+ supplierEmail?: string;
61
+ supplierPhone?: string;
62
+
63
+ // money-related details
64
+ firstInvoiceIssuedAt?: string;
65
+ lastInvoiceIssuedAt?: string;
66
+ firstPaymentAt?: string;
67
+ fullPaymentAt?: string;
68
+ expectedAmount: string;
69
+ actualAmount: string;
70
+
71
+ purchaseAt?: string; // this is the date that should be considered for the purchase according to TJ (often the same as fullPaymentAt)
72
+
73
+ // log
74
+ marketingAt?: string; // no vehicle in our parking, just digital marketing
75
+ evaluationAt?: string; // in consignation
76
+ purchaseAgreedAt?: string;
77
+ // firstPaymentAllowedAt?: string;
78
+ // firstPaymentSentAt?: string;
79
+ // fullPaymentAllowedAt?: string;
80
+ // fullPaymentSentAt?: string;
81
+ arrivedAt?: string;
82
+ checkedInAt?: string;
83
+
84
+ hasMainInvoice?: boolean;
85
+ };
86
+
87
+ export type VehicleProfitOverview = {
88
+ expectedProfit?: string;
89
+ expectedRoi?: string;
90
+
91
+ actualProfit?: string;
92
+ actualRoi?: string;
93
+ };
94
+
95
+ type VehicleSummary = {
96
+ branch: string;
97
+ stockNumber: string;
98
+ id: string;
99
+ };
100
+
101
+ export type VehicleBusinessOverview = {
102
+ vehicle: VehicleSummary;
103
+ purchase: VehiclePurchaseOverview;
104
+ sale?: VehicleSaleOverview;
105
+ profit?: VehicleProfitOverview;
106
+ };
@@ -49,7 +49,7 @@ export const getInternalTitle = ({
49
49
  bodywork?: string;
50
50
  }): string => {
51
51
  if (category === Categories.Trailer || category === Categories.SemiTrailer) {
52
- return [make, modelName, bodywork]
52
+ return [make, modelName, modelTypeName, bodywork]
53
53
  .filter((v): v is string => !!v)
54
54
  .map((v) => v.trim())
55
55
  .join(' ')