@bisondesk/core-sdk 1.0.594 → 1.0.597

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.
Files changed (135) hide show
  1. package/lib/apis/country-delivery.d.ts +3 -0
  2. package/lib/apis/country-delivery.d.ts.map +1 -0
  3. package/lib/apis/{country-pricing.js → country-delivery.js} +3 -3
  4. package/lib/apis/country-delivery.js.map +1 -0
  5. package/lib/types/country-delivery.d.ts +18 -0
  6. package/lib/types/country-delivery.d.ts.map +1 -0
  7. package/lib/types/country-delivery.js +2 -0
  8. package/lib/types/country-delivery.js.map +1 -0
  9. package/lib/types/exchange-rates.d.ts +6 -0
  10. package/lib/types/exchange-rates.d.ts.map +1 -0
  11. package/lib/types/exchange-rates.js +2 -0
  12. package/lib/types/exchange-rates.js.map +1 -0
  13. package/lib/types/opportunities.d.ts +2 -0
  14. package/lib/types/opportunities.d.ts.map +1 -1
  15. package/lib/types/opportunities.js.map +1 -1
  16. package/lib/types/quote-settings.d.ts +4 -0
  17. package/lib/types/quote-settings.d.ts.map +1 -1
  18. package/lib/types/quote-settings.js.map +1 -1
  19. package/lib/types/user-performance.d.ts +1 -0
  20. package/lib/types/user-performance.d.ts.map +1 -1
  21. package/lib/types/user-performance.js.map +1 -1
  22. package/lib/types/vehicles.d.ts +12 -7
  23. package/lib/types/vehicles.d.ts.map +1 -1
  24. package/lib/types/vehicles.js.map +1 -1
  25. package/lib/utils/exchange-rates.d.ts +3 -0
  26. package/lib/utils/exchange-rates.d.ts.map +1 -0
  27. package/lib/utils/exchange-rates.js +15 -0
  28. package/lib/utils/exchange-rates.js.map +1 -0
  29. package/lib/utils/exchange-rates.test.d.ts +2 -0
  30. package/lib/utils/exchange-rates.test.d.ts.map +1 -0
  31. package/lib/utils/exchange-rates.test.js +23 -0
  32. package/lib/utils/exchange-rates.test.js.map +1 -0
  33. package/lib/utils/vehicles.d.ts.map +1 -1
  34. package/lib/utils/vehicles.js +8 -0
  35. package/lib/utils/vehicles.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/apis/{country-pricing.ts → country-delivery.ts} +5 -3
  38. package/src/types/activities.js +13 -0
  39. package/src/types/activities.js.map +1 -0
  40. package/src/types/comparables.js +2 -0
  41. package/src/types/comparables.js.map +1 -0
  42. package/src/types/country-delivery.ts +42 -0
  43. package/src/types/crm.js +58 -0
  44. package/src/types/crm.js.map +1 -0
  45. package/src/types/dashboard.js +2 -0
  46. package/src/types/dashboard.js.map +1 -0
  47. package/src/types/definitions.js +2 -0
  48. package/src/types/definitions.js.map +1 -0
  49. package/src/types/exchange-rates.ts +10 -0
  50. package/src/types/fields.js +2 -0
  51. package/src/types/fields.js.map +1 -0
  52. package/src/types/insights.js +2 -0
  53. package/src/types/insights.js.map +1 -0
  54. package/src/types/interests.js +6 -0
  55. package/src/types/interests.js.map +1 -0
  56. package/src/types/internal-events.js +18 -0
  57. package/src/types/internal-events.js.map +1 -0
  58. package/src/types/internet-opportunities.js +2 -0
  59. package/src/types/internet-opportunities.js.map +1 -0
  60. package/src/types/internet-vehicles.js +2 -0
  61. package/src/types/internet-vehicles.js.map +1 -0
  62. package/src/types/leasing-administration.js +2 -0
  63. package/src/types/leasing-administration.js.map +1 -0
  64. package/src/types/leasing-debtors.js +2 -0
  65. package/src/types/leasing-debtors.js.map +1 -0
  66. package/src/types/leasing-search.js +2 -0
  67. package/src/types/leasing-search.js.map +1 -0
  68. package/src/types/leasing-settings.js +7 -0
  69. package/src/types/leasing-settings.js.map +1 -0
  70. package/src/types/leasing.js +38 -0
  71. package/src/types/leasing.js.map +1 -0
  72. package/src/types/marketing.js +35 -0
  73. package/src/types/marketing.js.map +1 -0
  74. package/src/types/offers.js +56 -0
  75. package/src/types/opportunities.js +107 -0
  76. package/src/types/opportunities.js.map +1 -0
  77. package/src/types/opportunities.ts +6 -0
  78. package/src/types/payments.js +7 -0
  79. package/src/types/picklists.js +2 -0
  80. package/src/types/picklists.js.map +1 -0
  81. package/src/types/quote-settings.ts +4 -0
  82. package/src/types/quotes.js +42 -0
  83. package/src/types/recently-viewed.js +2 -0
  84. package/src/types/recently-viewed.js.map +1 -0
  85. package/src/types/reservations.js +5 -0
  86. package/src/types/reservations.js.map +1 -0
  87. package/src/types/roi-ratings.js +5 -0
  88. package/src/types/roi-ratings.js.map +1 -0
  89. package/src/types/saved-filters.js +9 -0
  90. package/src/types/saved-filters.js.map +1 -0
  91. package/src/types/search.js +2 -0
  92. package/src/types/search.js.map +1 -0
  93. package/src/types/settings.js +2 -0
  94. package/src/types/settings.js.map +1 -0
  95. package/src/types/templates.js +2 -0
  96. package/src/types/templates.js.map +1 -0
  97. package/src/types/tenants.js +21 -0
  98. package/src/types/tenants.js.map +1 -0
  99. package/src/types/user-performance.js +7 -0
  100. package/src/types/user-performance.js.map +1 -0
  101. package/src/types/user-performance.ts +1 -0
  102. package/src/types/utils.js +2 -0
  103. package/src/types/validation.js +2 -0
  104. package/src/types/validation.js.map +1 -0
  105. package/src/types/vehicle-sales.js +6 -0
  106. package/src/types/vehicle-sales.js.map +1 -0
  107. package/src/types/vehicles.js +98 -0
  108. package/src/types/vehicles.js.map +1 -0
  109. package/src/types/vehicles.ts +40 -4
  110. package/src/utils/exchange-rates.test.ts +29 -0
  111. package/src/utils/exchange-rates.ts +32 -0
  112. package/src/utils/leasing.js +6 -0
  113. package/src/utils/leasing.js.map +1 -0
  114. package/src/utils/opportunities.js +48 -0
  115. package/src/utils/opportunities.js.map +1 -0
  116. package/src/utils/vehicles.ts +8 -0
  117. package/tsconfig.tsbuildinfo +1 -1
  118. package/lib/apis/country-pricing.d.ts +0 -3
  119. package/lib/apis/country-pricing.d.ts.map +0 -1
  120. package/lib/apis/country-pricing.js.map +0 -1
  121. package/lib/types/country-pricing.d.ts +0 -16
  122. package/lib/types/country-pricing.d.ts.map +0 -1
  123. package/lib/types/country-pricing.js +0 -2
  124. package/lib/types/country-pricing.js.map +0 -1
  125. package/lib/utils/country-pricing.d.ts +0 -5
  126. package/lib/utils/country-pricing.d.ts.map +0 -1
  127. package/lib/utils/country-pricing.js +0 -17
  128. package/lib/utils/country-pricing.js.map +0 -1
  129. package/lib/utils/country-pricing.test.d.ts +0 -2
  130. package/lib/utils/country-pricing.test.d.ts.map +0 -1
  131. package/lib/utils/country-pricing.test.js +0 -65
  132. package/lib/utils/country-pricing.test.js.map +0 -1
  133. package/src/types/country-pricing.ts +0 -25
  134. package/src/utils/country-pricing.test.ts +0 -82
  135. package/src/utils/country-pricing.ts +0 -44
@@ -530,15 +530,49 @@ export type VehicleExternalInfo = {
530
530
  leasing?: boolean;
531
531
  price?: string | undefined;
532
532
  currency?: string | undefined;
533
+ /**
534
+ * Read-only field maintained by `fillReadOnlyFields` on every vehicle save:
535
+ * the value of `price` immediately before the most recent price change. Stays
536
+ * unchanged when `price` does not change between saves. Same currency as
537
+ * `price`. Useful for storefront "was/now" price-drop labels and for the AI
538
+ * assistant's negotiation context.
539
+ */
540
+ previousPrice?: string;
533
541
  marginScheme?: boolean;
534
542
  manufacturerWarranty?: {
535
543
  remarks?: string;
536
544
  available?: boolean;
537
545
  };
538
- } & (
539
- | { deliveryCost: number; deliveryLocation: string }
540
- | { deliveryCost?: never; deliveryLocation?: never }
541
- );
546
+ /**
547
+ * Per-country snapshot computed by the owning tenant's `fillReadOnlyFields`.
548
+ * Every field on this snapshot is public — `vehicle.external` rides through
549
+ * to the storefront via cross-tenant sync, so internal-only values (e.g. the
550
+ * owner's freight cost) must not appear here. Cross-tenant sync derives the
551
+ * internal `externalTransport` figure directly from the owner's country-
552
+ * delivery rule at sync time.
553
+ *
554
+ * Each entry exposes:
555
+ * - `price` — bare currency conversion for the rule's country.
556
+ * - `previousPrice` — bare conversion of `salesConditions.previousPrice`
557
+ * when set.
558
+ * - `deliveryPrice` — customer-facing delivery fee (when the rule covers
559
+ * the vehicle's category). Storefront consumers sum
560
+ * `price + (deliveryPrice ?? 0)` at the display layer.
561
+ * - `deliveryLocation` — human-readable label, present whenever the rule
562
+ * declared a location for this country.
563
+ *
564
+ * Only the original owner recomputes on save; cross-tenant copies preserve
565
+ * the array.
566
+ */
567
+ localizedPricing?: Array<{
568
+ countryCode: string;
569
+ currency: string;
570
+ price: number;
571
+ previousPrice?: number;
572
+ deliveryPrice?: number;
573
+ deliveryLocation?: string;
574
+ }>;
575
+ };
542
576
  superstructure?: VehicleSuperstructure;
543
577
  weights?: {
544
578
  gvw?: number;
@@ -553,6 +587,7 @@ export type VehicleExternalInfo = {
553
587
  aluminiumFuelTank?: boolean;
554
588
  cdPlayer?: boolean;
555
589
  coil?: boolean;
590
+ doubleStock?: boolean;
556
591
  centralLocking?: boolean;
557
592
  centralLubrication?: boolean;
558
593
  cruiseControl?: boolean;
@@ -564,6 +599,7 @@ export type VehicleExternalInfo = {
564
599
  hydraulicTipperKit?: boolean;
565
600
  lowDeck?: boolean;
566
601
  lowNoise?: boolean;
602
+ mega?: boolean;
567
603
  parkingHeater?: boolean;
568
604
  particleFilter?: boolean;
569
605
  powerTakeOff?: boolean;
@@ -0,0 +1,29 @@
1
+ import { ExchangeRate } from '../types/exchange-rates.js';
2
+ import { convertCurrency } from './exchange-rates.js';
3
+
4
+ const rates: ExchangeRate[] = [
5
+ { fromCurrency: 'EUR', toCurrency: 'USD', rate: 1.2 },
6
+ { fromCurrency: 'EUR', toCurrency: 'XOF', rate: 655.96 },
7
+ ];
8
+
9
+ describe('convertCurrency', () => {
10
+ test('passthrough when from and to are equal', () => {
11
+ expect(convertCurrency(10000, 'EUR', 'EUR', rates)).toBe(10000);
12
+ });
13
+
14
+ test('uses the direct rate', () => {
15
+ expect(convertCurrency(10000, 'EUR', 'USD', rates)).toBe(12000);
16
+ });
17
+
18
+ test('uses the inverse rate when only the reverse is configured', () => {
19
+ expect(convertCurrency(12000, 'USD', 'EUR', rates)).toBe(Math.ceil(12000 / 1.2));
20
+ });
21
+
22
+ test('returns undefined when no pair matches', () => {
23
+ expect(convertCurrency(10000, 'BRL', 'USD', rates)).toBeUndefined();
24
+ });
25
+
26
+ test('uses Math.ceil to avoid underselling on partial units', () => {
27
+ expect(convertCurrency(999.5, 'EUR', 'USD', rates)).toBe(Math.ceil(999.5 * 1.2));
28
+ });
29
+ });
@@ -0,0 +1,32 @@
1
+ import { ExchangeRate } from '../types/exchange-rates.js';
2
+
3
+ /**
4
+ * Convert `amount` from `fromCurrency` to `toCurrency` using a direction-agnostic
5
+ * rate lookup. If a rate exists in either direction it is applied (inverted when
6
+ * needed). Returns `undefined` if no matching pair is configured.
7
+ *
8
+ * `Math.ceil` is applied on the result so the seller is never undersold by a
9
+ * partial unit of rounding.
10
+ */
11
+ export const convertCurrency = (
12
+ amount: number,
13
+ fromCurrency: string,
14
+ toCurrency: string,
15
+ rates: ExchangeRate[],
16
+ ): number | undefined => {
17
+ if (fromCurrency === toCurrency) {
18
+ return Math.ceil(amount);
19
+ }
20
+
21
+ const direct = rates.find((r) => r.fromCurrency === fromCurrency && r.toCurrency === toCurrency);
22
+ if (direct != null) {
23
+ return Math.ceil(amount * direct.rate);
24
+ }
25
+
26
+ const inverse = rates.find((r) => r.fromCurrency === toCurrency && r.toCurrency === fromCurrency);
27
+ if (inverse != null && inverse.rate > 0) {
28
+ return Math.ceil(amount / inverse.rate);
29
+ }
30
+
31
+ return undefined;
32
+ };
@@ -0,0 +1,6 @@
1
+ import { UTCDate } from '@date-fns/utc';
2
+ import { format } from 'date-fns';
3
+ import { last, map, sortBy, uniqBy } from 'lodash-es';
4
+ export const sortContractClients = (clients) => sortBy(map(uniqBy(clients, (c) => c.takeoverId), (c) => ({ ...c, since: format(new UTCDate(c.since), 'yyyy-MM-dd') })), (cli) => cli.since, (cli) => (cli.takeoverId ? parseInt(cli.takeoverId.replace(/[^0-9]/g, '')) : 0));
5
+ export const getDealRef = ({ conditions, opportunities, }) => last(conditions) ?? last(opportunities);
6
+ //# sourceMappingURL=leasing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leasing.js","sourceRoot":"","sources":["leasing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAStD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAgC,EAA2B,EAAE,CAC/F,MAAM,CACJ,GAAG,CACD,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,EACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CACrE,EACD,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,EAClB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAChF,CAAC;AAEJ,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EACzB,UAAU,EACV,aAAa,GACyC,EAAkC,EAAE,CAC1F,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,aAAa,CAAE,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { OpportunityStatus, OpportunityStatusOrder } from '../types/opportunities.js';
2
+ const compareOpportunityStatus = (input) => {
3
+ const { currentStatus, referenceStatus } = input;
4
+ const currentStatusIdx = OpportunityStatusOrder.indexOf(currentStatus);
5
+ const referenceStatusIdx = OpportunityStatusOrder.indexOf(referenceStatus);
6
+ return {
7
+ currentStatusIdx,
8
+ referenceStatusIdx,
9
+ };
10
+ };
11
+ export const getPreviousStatus = (currentStatus) => {
12
+ const currentIndex = OpportunityStatusOrder.indexOf(currentStatus);
13
+ if (currentIndex === 0) {
14
+ return;
15
+ }
16
+ return OpportunityStatusOrder[currentIndex - 1];
17
+ };
18
+ export const getNextStatus = (status) => {
19
+ const statusIndex = OpportunityStatusOrder.indexOf(status);
20
+ if (statusIndex >= OpportunityStatusOrder.length - 1) {
21
+ return;
22
+ }
23
+ return OpportunityStatusOrder[statusIndex + 1];
24
+ };
25
+ export const isSameOrAfterReferenceOpportunityStatus = (input) => {
26
+ const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);
27
+ return currentStatusIdx >= referenceStatusIdx;
28
+ };
29
+ export const isAfterReferenceOpportunityStatus = (input) => {
30
+ const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);
31
+ return currentStatusIdx > referenceStatusIdx;
32
+ };
33
+ export const isSameOrBeforeReferenceOpportunityStatus = (input) => {
34
+ const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);
35
+ return currentStatusIdx <= referenceStatusIdx;
36
+ };
37
+ export const isBeforeReferenceOpportunityStatus = (input) => {
38
+ const { currentStatusIdx, referenceStatusIdx } = compareOpportunityStatus(input);
39
+ return currentStatusIdx < referenceStatusIdx;
40
+ };
41
+ export const isOpportunityLost = (input) => input.lostAt != null;
42
+ export const getOpportunityReservedStatus = () => [
43
+ OpportunityStatus.REVIEW,
44
+ OpportunityStatus.PREPARATION,
45
+ OpportunityStatus.DELIVERY,
46
+ ];
47
+ export const isOpportunityReserved = (input) => getOpportunityReservedStatus().includes(input.status);
48
+ //# sourceMappingURL=opportunities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opportunities.js","sourceRoot":"","sources":["opportunities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAOnG,MAAM,wBAAwB,GAAG,CAAC,KAAmB,EAAE,EAAE;IACvD,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,GAAG,KAAK,CAAC;IAEjD,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACvE,MAAM,kBAAkB,GAAG,sBAAsB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAE3E,OAAO;QACL,gBAAgB;QAChB,kBAAkB;KACnB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,aAAgC,EACD,EAAE;IACjC,MAAM,YAAY,GAAG,sBAAsB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;IACT,CAAC;IACD,OAAO,sBAAsB,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAyB,EAAiC,EAAE;IACxF,MAAM,WAAW,GAAG,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,WAAW,IAAI,sBAAsB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO;IACT,CAAC;IACD,OAAO,sBAAsB,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uCAAuC,GAAG,CAAC,KAAmB,EAAW,EAAE;IACtF,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEjF,OAAO,gBAAgB,IAAI,kBAAkB,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAC,KAAmB,EAAW,EAAE;IAChF,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEjF,OAAO,gBAAgB,GAAG,kBAAkB,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,wCAAwC,GAAG,CAAC,KAAmB,EAAW,EAAE;IACvF,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEjF,OAAO,gBAAgB,IAAI,kBAAkB,CAAC;AAChD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kCAAkC,GAAG,CAAC,KAAmB,EAAW,EAAE;IACjF,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAEjF,OAAO,gBAAgB,GAAG,kBAAkB,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAkB,EAAW,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;AAEvF,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAwB,EAAE,CAAC;IACrE,iBAAiB,CAAC,MAAM;IACxB,iBAAiB,CAAC,WAAW;IAC7B,iBAAiB,CAAC,QAAQ;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAkB,EAAW,EAAE,CACnE,4BAA4B,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC"}
@@ -33,6 +33,14 @@ export const extractCustomFeatures = (vehicle: VehicleExternalInfo): string[] =>
33
33
  getValue: (vehicle) => vehicle.accessories.coil,
34
34
  picklistValueId: 'coil',
35
35
  },
36
+ {
37
+ getValue: (vehicle) => vehicle.accessories.doubleStock,
38
+ picklistValueId: 'doubleStock',
39
+ },
40
+ {
41
+ getValue: (vehicle) => vehicle.accessories.mega,
42
+ picklistValueId: 'mega',
43
+ },
36
44
  {
37
45
  getValue: (vehicle) => vehicle.salesConditions?.manufacturerWarranty?.available,
38
46
  picklistValueId: 'warranty',