@bisondesk/core-sdk 1.0.402 → 1.0.404

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.
@@ -1 +1 @@
1
- {"version":3,"file":"vehicles.js","sourceRoot":"/","sources":["utils/vehicles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAA4B,EAAY,EAAE;IAC9E,MAAM,QAAQ,GAGR;QACJ;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,KAAK,EAAE,OAAO;YAC7D,eAAe,EAAE,OAAO;SACzB;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,QAAQ,EAAE,OAAO;YAChE,eAAe,EAAE,UAAU;SAC5B;QACD,EAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE;QAC1E;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,gBAAgB;YAC3D,eAAe,EAAE,kBAAkB;SACpC;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,kBAAkB;YAC7D,eAAe,EAAE,oBAAoB;SACtC;QACD;YACE,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO;YAClD,eAAe,EAAE,SAAS;SAC3B;KACF,CAAC;IAEF,OAAO,QAAQ;SACZ,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SAChD,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAC/B,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAa,GAOd,EAAU,EAAE;IACX,IAAI,QAAQ,KAAK,UAAU,CAAC,OAAO,IAAI,QAAQ,KAAK,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3E,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;aAC/B,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;aAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,IAAI,CAAC,GAAG,CAAC;aACT,IAAI,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC;SACpC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,IAAI,CAAC,GAAG,CAAC;SACT,IAAI,EAAE,CAAC;AACZ,CAAC,CAAC;AAGF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,GAAW,EAAU,EAAE;IAC5D,MAAM,OAAO,GAAG,4BAA4B,CAAC;IAC7C,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAErC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,SAAS,GAAG,GAAG,GAAG,aAAa,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC;IAEjD,OAAO,sBAAsB,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;AAC1E,CAAC,CAAC","sourcesContent":["import { 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 make: string;\n category: 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\n// example: 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB, 52 -> AZ, 53 -> BA, 54 -> BB, 702 -> ZZ, 703 -> AAA\nexport const convertNumberToLetters = (num: number): string => {\n const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n const lettersLength = letters.length;\n\n if (num < 1) {\n return '';\n }\n\n const remainder = num % lettersLength;\n const quotient = Math.floor(num / lettersLength);\n\n return convertNumberToLetters(quotient) + letters.charAt(remainder - 1);\n};\n"]}
1
+ {"version":3,"file":"vehicles.js","sourceRoot":"/","sources":["utils/vehicles.ts"],"names":[],"mappings":"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","sourcesContent":["import { Categories } from '../constants.js';\nimport { VehicleExternalInfo } from '../types/vehicles.js';\nimport { XError } from '@bisondesk/commons-sdk/errors';\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 make: string;\n category: 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]{2}\\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 baseNumber = match[1];\n const counter = match[2];\n const counterNumber = convertLettersToNumber(counter);\n const nextCounterNumber = counterNumber + 1;\n const nextCounter = convertNumberToLetters(nextCounterNumber);\n return `${baseNumber}${nextCounter}`;\n};\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=vehicles.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vehicles.test.d.ts","sourceRoot":"/","sources":["utils/vehicles.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ import { convertLettersToNumber, convertNumberToLetters, getNextRelatedStockNumber, } from './vehicles.js';
2
+ import { XError } from '@bisondesk/commons-sdk/errors';
3
+ describe('stock number utils', () => {
4
+ describe('convertNumberToLetters', () => {
5
+ it('should convert numbers to letters correctly', () => {
6
+ expect(convertNumberToLetters(0)).toBe('');
7
+ expect(convertNumberToLetters(1)).toBe('A');
8
+ expect(convertNumberToLetters(2)).toBe('B');
9
+ expect(convertNumberToLetters(26)).toBe('Z');
10
+ expect(convertNumberToLetters(27)).toBe('AA');
11
+ expect(convertNumberToLetters(52)).toBe('AZ');
12
+ });
13
+ it('should return an empty string for numbers less than 1', () => {
14
+ expect(convertNumberToLetters(0)).toBe('');
15
+ expect(convertNumberToLetters(-1)).toBe('');
16
+ });
17
+ });
18
+ describe('convertLettersToNumber', () => {
19
+ it('should convert letters to numbers correctly', () => {
20
+ expect(convertLettersToNumber('')).toBe(0);
21
+ expect(convertLettersToNumber('A')).toBe(1);
22
+ expect(convertLettersToNumber('Z')).toBe(26);
23
+ expect(convertLettersToNumber('AA')).toBe(27);
24
+ expect(convertLettersToNumber('AZ')).toBe(52);
25
+ });
26
+ });
27
+ describe('getNextRelatedStockNumber', () => {
28
+ it('should get the next related stock number correctly', () => {
29
+ expect(getNextRelatedStockNumber('AB12345')).toBe('AB12345A');
30
+ expect(getNextRelatedStockNumber('AB12345A')).toBe('AB12345B');
31
+ expect(getNextRelatedStockNumber('AB12345Z')).toBe('AB12345AA');
32
+ expect(getNextRelatedStockNumber('AB12345AZ')).toBe('AB12345BA');
33
+ });
34
+ it('should throw an error for invalid stock numbers', () => {
35
+ expect(() => getNextRelatedStockNumber('12345')).toThrow(XError);
36
+ expect(() => getNextRelatedStockNumber('AB12345PPP')).toThrow(XError);
37
+ });
38
+ });
39
+ });
40
+ //# sourceMappingURL=vehicles.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vehicles.test.js","sourceRoot":"/","sources":["utils/vehicles.test.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n convertLettersToNumber,\n convertNumberToLetters,\n getNextRelatedStockNumber,\n} from './vehicles.js';\nimport { XError } from '@bisondesk/commons-sdk/errors';\n\ndescribe('stock number utils', () => {\n describe('convertNumberToLetters', () => {\n it('should convert numbers to letters correctly', () => {\n expect(convertNumberToLetters(0)).toBe('');\n expect(convertNumberToLetters(1)).toBe('A');\n expect(convertNumberToLetters(2)).toBe('B');\n expect(convertNumberToLetters(26)).toBe('Z');\n expect(convertNumberToLetters(27)).toBe('AA');\n expect(convertNumberToLetters(52)).toBe('AZ');\n });\n\n it('should return an empty string for numbers less than 1', () => {\n expect(convertNumberToLetters(0)).toBe('');\n expect(convertNumberToLetters(-1)).toBe('');\n });\n });\n\n describe('convertLettersToNumber', () => {\n it('should convert letters to numbers correctly', () => {\n expect(convertLettersToNumber('')).toBe(0);\n expect(convertLettersToNumber('A')).toBe(1);\n expect(convertLettersToNumber('Z')).toBe(26);\n expect(convertLettersToNumber('AA')).toBe(27);\n expect(convertLettersToNumber('AZ')).toBe(52);\n });\n });\n\n describe('getNextRelatedStockNumber', () => {\n it('should get the next related stock number correctly', () => {\n expect(getNextRelatedStockNumber('AB12345')).toBe('AB12345A');\n expect(getNextRelatedStockNumber('AB12345A')).toBe('AB12345B');\n expect(getNextRelatedStockNumber('AB12345Z')).toBe('AB12345AA');\n expect(getNextRelatedStockNumber('AB12345AZ')).toBe('AB12345BA');\n });\n\n it('should throw an error for invalid stock numbers', () => {\n expect(() => getNextRelatedStockNumber('12345')).toThrow(XError);\n expect(() => getNextRelatedStockNumber('AB12345PPP')).toThrow(XError);\n });\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bisondesk/core-sdk",
3
- "version": "1.0.402",
3
+ "version": "1.0.404",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "scripts": {
package/src/types/crm.ts CHANGED
@@ -129,6 +129,22 @@ export type CrmPublicSearchDefinitions = {
129
129
  searchContact: PublicSearchDefinition;
130
130
  };
131
131
 
132
+ export enum MarketingChannel {
133
+ Email = 'email',
134
+ Whatsapp = 'whatsapp',
135
+ Sms = 'sms',
136
+ Phone = 'phone',
137
+ }
138
+
139
+ export type MarketingPreferenceEntry = {
140
+ optedOut: boolean;
141
+ updatedAt: string;
142
+ };
143
+
144
+ export type MarketingPreferences = {
145
+ [channel in MarketingChannel]?: MarketingPreferenceEntry;
146
+ };
147
+
132
148
  type BaseContact = {
133
149
  accountManager?: string;
134
150
  countryCode?: string;
@@ -141,6 +157,7 @@ type BaseContact = {
141
157
  organizationId?: string;
142
158
  /** will not be filled if organizationId is present */
143
159
  orgName?: string;
160
+ marketingPreferences?: MarketingPreferences;
144
161
  };
145
162
 
146
163
  export type NewContact = BaseContact & {
@@ -1,10 +1,16 @@
1
- import { DistributiveOmit, Document, NextList } from '@bisondesk/commons-sdk/types';
1
+ import { DistributiveOmit, Document, LocationValue, NextList } from '@bisondesk/commons-sdk/types';
2
2
  import { BusinessEntityIds, WarningHints } from '../constants.js';
3
3
  import { Contact, Organization } from './crm.js';
4
4
  import { Insights, InsightsComparableSpecs } from './insights.js';
5
5
  import { BaseSearchRequest } from './search.js';
6
6
  import { DataRecord, ReferenceData } from './utils.js';
7
- import { VehicleExternalInfo } from './vehicles.js';
7
+ import {
8
+ SearchVehicle,
9
+ VehicleExternalInfo,
10
+ VehicleInternalInfo,
11
+ VehiclePurchaseDealStatus,
12
+ VehiclePurchaseDeliveryType,
13
+ } from './vehicles.js';
8
14
 
9
15
  export enum OfferActions {
10
16
  CREATE_BID = 'create_bid',
@@ -21,6 +27,7 @@ export enum OfferActions {
21
27
  ACCEPT_NEGOTIATION = 'accept_negotiation',
22
28
  UNDO_ACCEPT_NEGOTIATION = 'undo_accept_negotiation',
23
29
  SET_SUPPLIER_VEHICLE = 'set_supplier_vehicle',
30
+ CAN_PURCHASE = 'can_purchase',
24
31
  }
25
32
 
26
33
  export enum OfferBidActions {
@@ -77,6 +84,7 @@ type BaseOffer = {
77
84
  organizationId?: string;
78
85
 
79
86
  supplierNotes?: string; // Optional notes from the supplier
87
+ description: { remarks?: string; technicalRemarks?: string };
80
88
  };
81
89
 
82
90
  export type NewOffer = BaseOffer & {
@@ -133,6 +141,7 @@ export type OfferUpdate = {
133
141
 
134
142
  finalValuation?: string | null;
135
143
  agreed?: boolean;
144
+ description?: { remarks?: string; technicalRemarks?: string };
136
145
  };
137
146
 
138
147
  type OfferWarningActionLink = {
@@ -163,6 +172,7 @@ export type OfferMetadata = {
163
172
  export type OfferBff = {
164
173
  offer: DataRecord<Offer, OfferMetadata>;
165
174
  bids: DataRecord<OfferBid>[];
175
+ vehicles: SearchVehicle[];
166
176
  customer?: {
167
177
  contact: DataRecord<Contact>;
168
178
  org?: DataRecord<Organization>;
@@ -270,3 +280,46 @@ export type KanbanOffersNextList = Omit<
270
280
  > & {
271
281
  nextTokens?: Record<string, string | undefined>;
272
282
  };
283
+
284
+ /********
285
+ * Vehicle Purchase
286
+ */
287
+
288
+ export type OfferPurchase = {
289
+ offerId: string;
290
+ vin: string;
291
+ supplierStockNumber?: string;
292
+
293
+ deal: {
294
+ description: {
295
+ technicalRemarks: string;
296
+ };
297
+ dealStatus:
298
+ | VehiclePurchaseDealStatus.PurchaseEvaluation
299
+ | VehiclePurchaseDealStatus.PurchaseAgreed
300
+ | VehiclePurchaseDealStatus.Marketing;
301
+ costs: {
302
+ purchase: string;
303
+ purchaseVatPercentage: string;
304
+ internalGarage?: string;
305
+ externalGarage?: string;
306
+ internalTransport?: string;
307
+ externalTransport?: string;
308
+ other?: string;
309
+ commission?: string;
310
+ };
311
+ };
312
+
313
+ logistics: {
314
+ vehicleRole: VehicleInternalInfo['role'];
315
+ availabilityDate: string;
316
+ deliveryType?: VehiclePurchaseDeliveryType;
317
+ pickupAddress?: LocationValue;
318
+ };
319
+
320
+ salesPrices?: {
321
+ internet?: string;
322
+ premium?: string;
323
+ minimum?: string;
324
+ };
325
+ };
@@ -9,6 +9,14 @@ import {
9
9
  } from '@bisondesk/commons-sdk/types';
10
10
  import { OpportunityReservation } from './reservations.js';
11
11
 
12
+ export enum VehicleRoles {
13
+ SALE = 'SALE',
14
+ OWN_USE = 'OWN_USE',
15
+ RENTAL = 'RENTAL',
16
+ BUILD = 'BUILD',
17
+ UNKNOWN = 'UNKNOWN',
18
+ }
19
+
12
20
  type BaseVehicleEvent = {
13
21
  id: string;
14
22
  actionAt: string;
@@ -73,8 +81,8 @@ export type NewVehicleRequest = {
73
81
  technicalRemarks?: string;
74
82
  };
75
83
  logistics: {
76
- parking: string;
77
- deliveryType: VehiclePurchaseDeliveryType;
84
+ parking?: string;
85
+ deliveryType?: VehiclePurchaseDeliveryType;
78
86
  pickupAddress?: LocationValue;
79
87
  checkedInAt?: string;
80
88
  checkedInBy?: string;
@@ -95,13 +103,15 @@ export type NewVehicleRequest = {
95
103
  };
96
104
  vinList?: string;
97
105
  deal: {
106
+ offerId?: string;
98
107
  stockNumber?: string;
99
108
  contactId: string;
100
109
  orgId: string;
101
110
  purchasedBy: string;
102
111
  dealStatus:
103
112
  | VehiclePurchaseDealStatus.PurchaseEvaluation
104
- | VehiclePurchaseDealStatus.PurchaseAgreed;
113
+ | VehiclePurchaseDealStatus.PurchaseAgreed
114
+ | VehiclePurchaseDealStatus.Marketing;
105
115
  costs: {
106
116
  purchase: string;
107
117
  purchaseVatPercentage: string;
@@ -114,7 +124,7 @@ export type NewVehicleRequest = {
114
124
  };
115
125
  logistics: {
116
126
  availableDate: string;
117
- vehicleRole: VehicleInternalInfo['role'];
127
+ vehicleRole: VehicleRoles;
118
128
  };
119
129
  };
120
130
  };
@@ -257,6 +267,8 @@ export type VehicleInternalInfo = {
257
267
  stockNumber: string;
258
268
  branch: string;
259
269
 
270
+ offerId?: string;
271
+
260
272
  /**
261
273
  * This ID is used to link different vehicle objects that represent the same real world asset.
262
274
  * Ideally the chassis number could be used, but in some cases it is not available yet.
@@ -267,7 +279,7 @@ export type VehicleInternalInfo = {
267
279
  pictures: AttachmentValue[];
268
280
  engineeringDocs: Document[];
269
281
  pricing: VehiclePricing;
270
- role: 'SALE' | 'OWN_USE' | 'RENTAL' | 'BUILD' | 'UNKNOWN';
282
+ role: VehicleRoles;
271
283
  status: VehicleStatus;
272
284
  updatedAt: string;
273
285
  /* use this property to store additional terms that you want the vehicle to be found with when doing a full text search */
@@ -517,6 +529,7 @@ export enum VehiclePurchaseDealStatus {
517
529
  FirstPaymentSent = 'FIRST_PAYMENT_SENT',
518
530
  FullPaymentAllowed = 'FULL_PAYMENT_ALLOWED',
519
531
  FullPaymentSent = 'FULL_PAYMENT_SENT',
532
+ Marketing = 'MARKETING',
520
533
  }
521
534
 
522
535
  export enum VehiclePurchaseLogisticsStatus {
@@ -600,8 +613,12 @@ export type VehiclePurchase = {
600
613
 
601
614
  arrivedAt?: string;
602
615
  arrivedBy?: string;
616
+
603
617
  checkedInAt?: string;
604
618
  checkedInBy?: string;
619
+
620
+ marketingStartedAt?: string;
621
+ marketingStartedBy?: string;
605
622
  };
606
623
 
607
624
  deal: {
@@ -0,0 +1,48 @@
1
+ import {
2
+ convertLettersToNumber,
3
+ convertNumberToLetters,
4
+ getNextRelatedStockNumber,
5
+ } from './vehicles.js';
6
+ import { XError } from '@bisondesk/commons-sdk/errors';
7
+
8
+ describe('stock number utils', () => {
9
+ describe('convertNumberToLetters', () => {
10
+ it('should convert numbers to letters correctly', () => {
11
+ expect(convertNumberToLetters(0)).toBe('');
12
+ expect(convertNumberToLetters(1)).toBe('A');
13
+ expect(convertNumberToLetters(2)).toBe('B');
14
+ expect(convertNumberToLetters(26)).toBe('Z');
15
+ expect(convertNumberToLetters(27)).toBe('AA');
16
+ expect(convertNumberToLetters(52)).toBe('AZ');
17
+ });
18
+
19
+ it('should return an empty string for numbers less than 1', () => {
20
+ expect(convertNumberToLetters(0)).toBe('');
21
+ expect(convertNumberToLetters(-1)).toBe('');
22
+ });
23
+ });
24
+
25
+ describe('convertLettersToNumber', () => {
26
+ it('should convert letters to numbers correctly', () => {
27
+ expect(convertLettersToNumber('')).toBe(0);
28
+ expect(convertLettersToNumber('A')).toBe(1);
29
+ expect(convertLettersToNumber('Z')).toBe(26);
30
+ expect(convertLettersToNumber('AA')).toBe(27);
31
+ expect(convertLettersToNumber('AZ')).toBe(52);
32
+ });
33
+ });
34
+
35
+ describe('getNextRelatedStockNumber', () => {
36
+ it('should get the next related stock number correctly', () => {
37
+ expect(getNextRelatedStockNumber('AB12345')).toBe('AB12345A');
38
+ expect(getNextRelatedStockNumber('AB12345A')).toBe('AB12345B');
39
+ expect(getNextRelatedStockNumber('AB12345Z')).toBe('AB12345AA');
40
+ expect(getNextRelatedStockNumber('AB12345AZ')).toBe('AB12345BA');
41
+ });
42
+
43
+ it('should throw an error for invalid stock numbers', () => {
44
+ expect(() => getNextRelatedStockNumber('12345')).toThrow(XError);
45
+ expect(() => getNextRelatedStockNumber('AB12345PPP')).toThrow(XError);
46
+ });
47
+ });
48
+ });
@@ -1,5 +1,6 @@
1
1
  import { Categories } from '../constants.js';
2
2
  import { VehicleExternalInfo } from '../types/vehicles.js';
3
+ import { XError } from '@bisondesk/commons-sdk/errors';
3
4
 
4
5
  export const extractCustomFeatures = (vehicle: VehicleExternalInfo): string[] => {
5
6
  const features: {
@@ -62,17 +63,53 @@ export const getInternalTitle = ({
62
63
  .trim();
63
64
  };
64
65
 
65
- // example: 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB, 52 -> AZ, 53 -> BA, 54 -> BB, 702 -> ZZ, 703 -> AAA
66
+ const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
67
+
68
+ // example: 1 -> A, 2 -> B, 26 -> Z, 27 -> AA, 28 -> AB, 52 -> AZ, 53 -> BA, 54 -> BB, 702 -> ZZ
66
69
  export const convertNumberToLetters = (num: number): string => {
67
- const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
68
- const lettersLength = letters.length;
70
+ const lettersLength = ALPHABET.length;
69
71
 
70
72
  if (num < 1) {
71
73
  return '';
72
74
  }
73
75
 
74
- const remainder = num % lettersLength;
75
- const quotient = Math.floor(num / lettersLength);
76
+ let remainder = num % lettersLength;
77
+ let quotient = Math.floor(num / lettersLength);
78
+
79
+ // If remainder is 0, it means we should map it to 'Z' and reduce the quotient by 1
80
+ if (remainder === 0) {
81
+ remainder = lettersLength;
82
+ quotient -= 1;
83
+ }
84
+
85
+ return convertNumberToLetters(quotient) + ALPHABET.charAt(remainder - 1);
86
+ };
87
+
88
+ // example: A -> 1, B -> 2, Z -> 26, AA -> 27, AB -> 28, AZ -> 52, BA -> 53, BB -> 54, ZZ -> 702
89
+ export const convertLettersToNumber = (letters: string): number => {
90
+ const base = ALPHABET.length;
91
+
92
+ let result = 0;
93
+
94
+ for (let i = 0; i < letters.length; i++) {
95
+ const charValue = ALPHABET.indexOf(letters[i]) + 1;
96
+ result = result * base + charValue;
97
+ }
98
+
99
+ return result;
100
+ };
101
+
102
+ export const getNextRelatedStockNumber = (stockNumber: string): string => {
103
+ const counterPattern = /^([A-Z]{2}\d{5})([A-Z]{0,2})$/;
104
+ const match = stockNumber.match(counterPattern);
105
+ if (match == null) {
106
+ throw new XError('core-sdk.vehicles.bad-stock-number', { stockNumber });
107
+ }
76
108
 
77
- return convertNumberToLetters(quotient) + letters.charAt(remainder - 1);
109
+ const baseNumber = match[1];
110
+ const counter = match[2];
111
+ const counterNumber = convertLettersToNumber(counter);
112
+ const nextCounterNumber = counterNumber + 1;
113
+ const nextCounter = convertNumberToLetters(nextCounterNumber);
114
+ return `${baseNumber}${nextCounter}`;
78
115
  };