@bisondesk/core-sdk 1.0.607 → 1.0.609

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.
@@ -66,6 +66,13 @@ export type SalesReportSalesperson = {
66
66
  yoyPct: number | null;
67
67
  };
68
68
 
69
+ export type SalesReportMake = {
70
+ /** Vehicle make name from `vehicle.external.general.make` (stored verbatim, e.g. "DAF"). */
71
+ make: string;
72
+ units: number;
73
+ yoyPct: number | null;
74
+ };
75
+
69
76
  /** A conglomerate-flagged organization (there is no group/parent model — each org stands alone). */
70
77
  export type SalesReportConglomerateOrg = {
71
78
  /** `org.id`. */
@@ -116,6 +123,8 @@ export type SalesReportResponse = {
116
123
  };
117
124
  /** Top countries by units in the current window. */
118
125
  countries: SalesReportCountry[];
126
+ /** Top vehicle makes by units in the current window (the client slices to its top N). */
127
+ makes: SalesReportMake[];
119
128
  /** All sales people with units in either window (capped; the client list scrolls). */
120
129
  salespeople: SalesReportSalesperson[];
121
130
  /** Returning-customer tenure shares (4 buckets). */
@@ -61,12 +61,16 @@ export type Tenant = PublicTenant & {
61
61
  };
62
62
  };
63
63
 
64
+ export type AccountingProvider = 'exact' | 'odoo';
65
+
64
66
  export type Branch = {
65
67
  id: string;
66
68
  name: string;
67
69
  country: string;
68
70
  language: string;
71
+ /* deprecated — use `accounting === 'exact'` instead. Kept until prod cutover. */
69
72
  exactAccounting?: boolean;
73
+ accounting?: AccountingProvider;
70
74
  currency: string;
71
75
  adminNumberPrefix: string;
72
76
  stockNumberPrefix: string;
@@ -151,6 +151,7 @@ export type PerformanceVehicle = {
151
151
  sellerId?: string;
152
152
  purchaseAt?: string;
153
153
  purchaserId?: string;
154
+ customerName?: string;
154
155
  };
155
156
 
156
157
  export type PerformanceVehiclesRequest = {
@@ -0,0 +1,89 @@
1
+ import { Branch, Tenant } from '../types/tenants.js';
2
+ import { branchHasAccounting, branchProvider, tenantHasAccounting } from './accounting.js';
3
+
4
+ const makeBranch = (overrides: Partial<Branch> = {}): Branch => ({
5
+ id: 'b1',
6
+ name: 'Branch 1',
7
+ country: 'ci',
8
+ language: 'fr',
9
+ currency: 'XOF',
10
+ adminNumberPrefix: '',
11
+ stockNumberPrefix: '',
12
+ vatNumber: '',
13
+ vatRates: { standard: '18' },
14
+ location: { country: 'ci' },
15
+ ...overrides,
16
+ });
17
+
18
+ const makeTenant = (branches: Branch[], overrides: Partial<Tenant> = {}): Tenant =>
19
+ ({
20
+ id: 't',
21
+ name: 't',
22
+ region: 'eu-west-1',
23
+ defaultCountry: 'ci',
24
+ defaultCurrency: 'XOF',
25
+ defaultLanguage: 'fr',
26
+ subdomains: ['t'],
27
+ languages: ['fr'],
28
+ emailDomain: 'example.com',
29
+ branches: branches as [Branch, ...Branch[]],
30
+ modules: [],
31
+ opportunities: { types: [] },
32
+ ...overrides,
33
+ }) as Tenant;
34
+
35
+ describe('branchProvider', () => {
36
+ it('returns undefined for missing branch', () => {
37
+ expect(branchProvider(undefined)).toBeUndefined();
38
+ });
39
+
40
+ it('prefers the new discriminator over the legacy boolean', () => {
41
+ const branch = makeBranch({ accounting: 'odoo', exactAccounting: true });
42
+ expect(branchProvider(branch)).toBe('odoo');
43
+ });
44
+
45
+ it('falls back to legacy boolean as exact', () => {
46
+ const branch = makeBranch({ exactAccounting: true });
47
+ expect(branchProvider(branch)).toBe('exact');
48
+ });
49
+
50
+ it('returns undefined when neither field is set', () => {
51
+ expect(branchProvider(makeBranch())).toBeUndefined();
52
+ });
53
+
54
+ it('returns undefined when legacy boolean is false', () => {
55
+ expect(branchProvider(makeBranch({ exactAccounting: false }))).toBeUndefined();
56
+ });
57
+ });
58
+
59
+ describe('branchHasAccounting', () => {
60
+ it('is true when accounting is set', () => {
61
+ expect(branchHasAccounting(makeBranch({ accounting: 'odoo' }))).toBe(true);
62
+ });
63
+
64
+ it('is true when legacy exactAccounting is true', () => {
65
+ expect(branchHasAccounting(makeBranch({ exactAccounting: true }))).toBe(true);
66
+ });
67
+
68
+ it('is false otherwise', () => {
69
+ expect(branchHasAccounting(makeBranch())).toBe(false);
70
+ expect(branchHasAccounting(undefined)).toBe(false);
71
+ });
72
+ });
73
+
74
+ describe('tenantHasAccounting', () => {
75
+ it('is true when tenant-level legacy flag is set', () => {
76
+ const tenant = makeTenant([makeBranch()], { exactAccounting: true });
77
+ expect(tenantHasAccounting(tenant)).toBe(true);
78
+ });
79
+
80
+ it('is true when any branch has accounting', () => {
81
+ const tenant = makeTenant([makeBranch(), makeBranch({ id: 'b2', accounting: 'odoo' })]);
82
+ expect(tenantHasAccounting(tenant)).toBe(true);
83
+ });
84
+
85
+ it('is false when no branch has accounting and tenant flag is not set', () => {
86
+ expect(tenantHasAccounting(makeTenant([makeBranch()]))).toBe(false);
87
+ expect(tenantHasAccounting(undefined)).toBe(false);
88
+ });
89
+ });
@@ -0,0 +1,24 @@
1
+ import { AccountingProvider, Branch, Tenant } from '../types/tenants.js';
2
+
3
+ export const branchProvider = (branch: Branch | undefined): AccountingProvider | undefined => {
4
+ if (branch == null) {
5
+ return undefined;
6
+ }
7
+ if (branch.accounting != null) {
8
+ return branch.accounting;
9
+ }
10
+ return branch.exactAccounting ? 'exact' : undefined;
11
+ };
12
+
13
+ export const branchHasAccounting = (branch: Branch | undefined): boolean =>
14
+ branchProvider(branch) != null;
15
+
16
+ export const tenantHasAccounting = (tenant: Tenant | undefined): boolean => {
17
+ if (tenant == null) {
18
+ return false;
19
+ }
20
+ if (tenant.exactAccounting) {
21
+ return true;
22
+ }
23
+ return tenant.branches.some((b) => branchHasAccounting(b));
24
+ };