@bisondesk/core-sdk 1.0.616 → 1.0.618
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.
- package/lib/types/opportunities.d.ts +31 -2
- package/lib/types/opportunities.d.ts.map +1 -1
- package/lib/types/opportunities.js.map +1 -1
- package/lib/types/quotes.d.ts +6 -0
- package/lib/types/quotes.d.ts.map +1 -1
- package/lib/types/quotes.js +5 -0
- package/lib/types/quotes.js.map +1 -1
- package/lib/types/reports-leasing.d.ts +1 -0
- package/lib/types/reports-leasing.d.ts.map +1 -1
- package/lib/types/reports-leasing.js.map +1 -1
- package/lib/types/reports-sales.d.ts +9 -0
- package/lib/types/reports-sales.d.ts.map +1 -1
- package/lib/types/reports-sales.js.map +1 -1
- package/lib/types/tenants.d.ts +7 -0
- package/lib/types/tenants.d.ts.map +1 -1
- package/lib/types/tenants.js +2 -0
- package/lib/types/tenants.js.map +1 -1
- package/package.json +1 -1
- package/src/types/opportunities.ts +32 -2
- package/src/types/quotes.ts +11 -2
- package/src/types/reports-leasing.ts +17 -4
- package/src/types/reports-sales.ts +16 -0
- package/src/types/tenants.ts +15 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reports-sales.js","sourceRoot":"/","sources":["types/reports-sales.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,WAAW;IACX,KAAK;IACL,KAAK;IACL,UAAU;IACV,KAAK;CACG,CAAC;AAIX,MAAM,CAAC,MAAM,oBAAoB,GAAmB,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"reports-sales.js","sourceRoot":"/","sources":["types/reports-sales.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,WAAW;IACX,KAAK;IACL,KAAK;IACL,UAAU;IACV,KAAK;CACG,CAAC;AAIX,MAAM,CAAC,MAAM,oBAAoB,GAAmB,KAAK,CAAC;AA+F1D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC","sourcesContent":["/**\n * Sales report — the payload for the `Reports → Sales` tab. Sales-side metrics\n * are computed from the per-tenant `opportunities` OpenSearch index, keyed on\n * `opportunity.reviewedAt` (the moment an opportunity ENTERS Preparation — our\n * \"sale\" event; `preparedAt` is when it leaves Preparation into Delivery). The\n * buyer ranking comes from the vehicles index, keyed on `purchase.purchaseAgreedAt`.\n *\n * The API returns raw numbers only; the client formats (€, %, pp, \"younger\") and\n * colors the deltas.\n */\n\n/**\n * Period presets driving every metric except the fixed 18-month histogram, in\n * selector order. Single source of truth — `SalesPeriodKey` is derived from it.\n * `mtd`/`ytd` are to-date ranges (start of month/year → now); `lastMonth`/`lastYear`\n * are the previous complete calendar month/year.\n */\nexport const SALES_PERIOD_KEYS = [\n '30d',\n '45d',\n '60d',\n '90d',\n 'lastMonth',\n 'mtd',\n 'ytd',\n 'lastYear',\n '12m',\n] as const;\n\nexport type SalesPeriodKey = (typeof SALES_PERIOD_KEYS)[number];\n\nexport const DEFAULT_SALES_PERIOD: SalesPeriodKey = 'mtd';\n\nexport type SalesReportRequest = { period: SalesPeriodKey };\n\n/**\n * A metric for the selected window with its year-over-year counterpart.\n * - `value`: current window (null when undefined, e.g. no data / no median).\n * - `prev`: same metric in the window shifted back exactly one year.\n * - `pct`: fractional change `(value - prev) / prev` (null when prev is 0 or\n * either side is undefined). The client renders/colors the delta.\n */\nexport type YoyMetric = { value: number | null; prev: number | null; pct: number | null };\n\n/** Tenure buckets for returning-customer analysis (share of buyers in the window). */\nexport type TenureBucketKey = '2y' | '1-2y' | '<1y' | 'new';\n\nexport type TenureBucket = {\n bucket: TenureBucketKey;\n /** Share of buyers in this bucket, 0–100. */\n sharePct: number;\n /** Year-over-year change in this share, as a fractional relative change (null when no prior data). */\n yoyPct: number | null;\n};\n\nexport type SalesReportCountry = {\n /** ISO country code (lowercase) from `org.countryCode`. */\n code: string;\n units: number;\n yoyPct: number | null;\n};\n\nexport type SalesReportSalesperson = {\n /** User id from `opportunity.accountManager`; the client resolves name + avatar. */\n id: string;\n units: number;\n yoyPct: number | null;\n};\n\nexport type SalesReportBuyer = {\n /** User id from `purchase.purchasedBy`; the client resolves name + avatar. */\n id: string;\n units: number;\n yoyPct: number | null;\n};\n\nexport type SalesReportMake = {\n /** Vehicle make name from `vehicle.external.general.make` (stored verbatim, e.g. \"DAF\"). */\n make: string;\n units: number;\n yoyPct: number | null;\n};\n\n/** A ranked organization row for the top-clients / top-suppliers cards. */\nexport type SalesReportTopOrg = {\n /** Organization id (`org.id` for clients; `purchase.organizationId` for suppliers). */\n id: string;\n /** Organization name (resolved server-side); falls back to the id when missing. */\n name: string;\n /** The org's ISO country code (lowercase); null when not recorded. */\n countryCode: string | null;\n units: number;\n yoyPct: number | null;\n};\n\n/** A conglomerate-flagged organization (there is no group/parent model — each org stands alone). */\nexport type SalesReportConglomerateOrg = {\n /** `org.id`. */\n id: string;\n /** `org.name` (resolved server-side); falls back to the id when missing. */\n name: string;\n units: number;\n yoyPct: number | null;\n};\n\nexport type SalesReportConglomerate = {\n /** Share of units going to conglomerate-flagged customers, 0–100 (null when no sales). */\n sharePct: number | null;\n /** Year-over-year change in that share, as a fractional relative change (null when no prior data). */\n yoyPct: number | null;\n /** The conglomerate share in the year-ago window, 0–100. */\n lastYearPct: number | null;\n /** Top conglomerate-flagged organizations by units in the current window. */\n orgs: SalesReportConglomerateOrg[];\n};\n\nexport type SalesReportHistogramBucket = {\n /** Calendar month, `YYYY-MM`. */\n month: string;\n count: number;\n};\n\n/**\n * Age-of-stock bands, in days of capital tied up. Cut points at 30 / 90 / 180 days,\n * upper bound inclusive; the last band is open-ended, so `180+` means \"181 and over\".\n */\nexport const STOCK_AGE_BANDS = ['0-30', '31-90', '91-180', '180+'] as const;\n\nexport type StockAgeBand = (typeof STOCK_AGE_BANDS)[number];\n\n/**\n * One day on the stock-age chart, measured by capital tied up in inventory. A vehicle\n * counts on `date` when the supplier was fully paid on or before that day and it had not\n * been sold yet; its age is `date − supplierFullyPaidAt` in days. Used vehicles only.\n */\nexport type StockAgePoint = {\n /** Snapshot day, `YYYY-MM-DD` (UTC). */\n date: string;\n /** In-stock vehicle count per age band on that day. */\n counts: Record<StockAgeBand, number>;\n};\n\nexport type SalesReportResponse = {\n period: {\n key: SalesPeriodKey;\n /** Current window, half-open `[start, end)` (ISO strings). */\n start: string;\n end: string;\n /** Number of days in the window (the `salesPerDay` denominator). */\n days: number;\n /** Year-ago window `[yoyStart, yoyEnd)`. */\n yoyStart: string;\n yoyEnd: string;\n };\n /** All-types overview KPIs. `medianAge` is in years (a decrease is good — younger stock). */\n overview: {\n salesPerDay: YoyMetric;\n salesTotal: YoyMetric;\n medianRoi: YoyMetric;\n medianPrice: YoyMetric;\n medianAge: YoyMetric;\n uniqueCustomers: YoyMetric;\n };\n /** Top countries by units in the current window. */\n countries: SalesReportCountry[];\n /** Top vehicle makes by units in the current window (the client slices to its top N). */\n makes: SalesReportMake[];\n /** All sales people with units in either window (capped; the client list scrolls). */\n salespeople: SalesReportSalesperson[];\n /** All purchasers with vehicles bought in the current window (capped; the client list scrolls). */\n buyers: SalesReportBuyer[];\n /** Top client organizations by units bought from us in the current window. */\n topClients: SalesReportTopOrg[];\n /** Top supplier organizations by used vehicles purchased from them in the current window. */\n topSuppliers: SalesReportTopOrg[];\n /** Returning-customer tenure shares (4 buckets). */\n returning: TenureBucket[];\n conglomerate: SalesReportConglomerate;\n /** Fixed last-18-calendar-months histogram of opps into Preparation (period-independent). */\n histogram: SalesReportHistogramBucket[];\n /**\n * Stock-age evolution measured as capital tied up in inventory: one daily snapshot of\n * vehicles by days from supplier-fully-paid to sold (used vehicles). Fixed to the last\n * 6 months, period-independent.\n */\n stockAge: StockAgePoint[];\n /**\n * Customer concentration: the 10 largest customers' share of units in the window, as a\n * fraction (0–1); null when there are no sales. A risk signal — over-reliance on a few\n * buyers.\n */\n concentration: number | null;\n};\n"]}
|
package/lib/types/tenants.d.ts
CHANGED
|
@@ -27,10 +27,13 @@ export declare enum TenantModule {
|
|
|
27
27
|
Bootstrap = "bootstrap",
|
|
28
28
|
WhatsappNotifications = "whatsapp_notifications",
|
|
29
29
|
Hexon = "hexon",
|
|
30
|
+
DeliveryConfirmation = "delivery_confirmation",
|
|
30
31
|
Transport = "transport",
|
|
31
32
|
Reports = "reports",
|
|
32
33
|
Prospects = "prospects"
|
|
33
34
|
}
|
|
35
|
+
export declare const REPORT_TAB_KEYS: readonly ["sales", "leasing", "purchases"];
|
|
36
|
+
export type ReportTabKey = (typeof REPORT_TAB_KEYS)[number];
|
|
34
37
|
export type Tenant = PublicTenant & {
|
|
35
38
|
cognito?: CognitoInfo;
|
|
36
39
|
languages: [string, ...string[]];
|
|
@@ -41,6 +44,9 @@ export type Tenant = PublicTenant & {
|
|
|
41
44
|
exactAccounting?: boolean;
|
|
42
45
|
branches: [Branch, ...Branch[]];
|
|
43
46
|
modules: TenantModule[];
|
|
47
|
+
reports?: {
|
|
48
|
+
tabs: ReportTabKey[];
|
|
49
|
+
};
|
|
44
50
|
test?: boolean;
|
|
45
51
|
opportunities: {
|
|
46
52
|
types: OpportunityType[];
|
|
@@ -52,6 +58,7 @@ export type Tenant = PublicTenant & {
|
|
|
52
58
|
costCenterPerLine?: boolean;
|
|
53
59
|
};
|
|
54
60
|
defaultTwilioPhoneNumber?: string;
|
|
61
|
+
deliveryEmail?: string;
|
|
55
62
|
};
|
|
56
63
|
export type AccountingProvider = 'exact' | 'odoo';
|
|
57
64
|
export type Branch = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenants.d.ts","sourceRoot":"/","sources":["types/tenants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;CAInC,CAAC;AAEF,oBAAY,YAAY;IACtB,cAAc,mBAAmB;IACjC,GAAG,QAAQ;IACX,GAAG,QAAQ;IACX,IAAI,SAAS;IACb,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,SAAS,cAAc;IACvB,QAAQ,aAAa;IACrB,aAAa,kBAAkB;IAC/B,MAAM,WAAW;IACjB,kBAAkB,yBAAyB;IAC3C,QAAQ,aAAa;IACrB,KAAK,UAAU;IACf,aAAa,oBAAoB;IACjC,SAAS,cAAc;IACvB,qBAAqB,2BAA2B;IAChD,KAAK,UAAU;IACf,SAAS,cAAc;IACvB,OAAO,YAAY;IACnB,SAAS,cAAc;CACxB;
|
|
1
|
+
{"version":3,"file":"tenants.d.ts","sourceRoot":"/","sources":["types/tenants.ts"],"names":[],"mappings":"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"}
|
package/lib/types/tenants.js
CHANGED
|
@@ -17,8 +17,10 @@ export var TenantModule;
|
|
|
17
17
|
TenantModule["Bootstrap"] = "bootstrap";
|
|
18
18
|
TenantModule["WhatsappNotifications"] = "whatsapp_notifications";
|
|
19
19
|
TenantModule["Hexon"] = "hexon";
|
|
20
|
+
TenantModule["DeliveryConfirmation"] = "delivery_confirmation";
|
|
20
21
|
TenantModule["Transport"] = "transport";
|
|
21
22
|
TenantModule["Reports"] = "reports";
|
|
22
23
|
TenantModule["Prospects"] = "prospects";
|
|
23
24
|
})(TenantModule || (TenantModule = {}));
|
|
25
|
+
export const REPORT_TAB_KEYS = ['sales', 'leasing', 'purchases'];
|
|
24
26
|
//# sourceMappingURL=tenants.js.map
|
package/lib/types/tenants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenants.js","sourceRoot":"/","sources":["types/tenants.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"tenants.js","sourceRoot":"/","sources":["types/tenants.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAN,IAAY,YAsBX;AAtBD,WAAY,YAAY;IACtB,iDAAiC,CAAA;IACjC,2BAAW,CAAA;IACX,2BAAW,CAAA;IACX,6BAAa,CAAA;IACb,+BAAe,CAAA;IACf,mCAAmB,CAAA;IACnB,uCAAuB,CAAA;IACvB,qCAAqB,CAAA;IACrB,+CAA+B,CAAA;IAC/B,iCAAiB,CAAA;IACjB,2DAA2C,CAAA;IAC3C,qCAAqB,CAAA;IACrB,+BAAe,CAAA;IACf,iDAAiC,CAAA;IACjC,uCAAuB,CAAA;IACvB,gEAAgD,CAAA;IAChD,+BAAe,CAAA;IACf,8DAA8C,CAAA;IAC9C,uCAAuB,CAAA;IACvB,mCAAmB,CAAA;IACnB,uCAAuB,CAAA;AACzB,CAAC,EAtBW,YAAY,KAAZ,YAAY,QAsBvB;AAGD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,WAAW,CAAU,CAAC","sourcesContent":["import { CognitoInfo, LocationValue, Region } from '@bisondesk/commons-sdk/types';\nimport { OpportunityType } from '../constants.js';\n\nexport type PublicTenant = {\n defaultCountry: string;\n defaultCurrency: string;\n defaultLanguage: string;\n id: string; // the id is provided on creation bc we assume tenants will be created by someone on the team\n name: string;\n region: Region;\n subdomains: [string, ...string[]];\n\n // Pay attention to what information is added here since\n // the tenant can be obtained without authentication\n};\n\nexport enum TenantModule {\n Administration = 'administration',\n App = 'app',\n CRM = 'crm',\n Docs = 'docs',\n Leads = 'leads',\n Leasing = 'leasing',\n Marketing = 'marketing',\n Insights = 'insights',\n Opportunities = 'opportunities',\n Offers = 'offers',\n VehiclesMasterData = 'vehicles_master_data',\n Vehicles = 'vehicles',\n Tasks = 'tasks',\n TrackAndTrace = 'track_and_trace',\n Bootstrap = 'bootstrap',\n WhatsappNotifications = 'whatsapp_notifications',\n Hexon = 'hexon',\n DeliveryConfirmation = 'delivery_confirmation',\n Transport = 'transport',\n Reports = 'reports',\n Prospects = 'prospects',\n}\n\n/** Report tabs a tenant can enable, in canonical order. */\nexport const REPORT_TAB_KEYS = ['sales', 'leasing', 'purchases'] as const;\n\nexport type ReportTabKey = (typeof REPORT_TAB_KEYS)[number];\n\nexport type Tenant = PublicTenant & {\n cognito?: CognitoInfo;\n languages: [string, ...string[]];\n conglomerate?: string;\n emailDomain: string;\n hyperdmsIds?: string[];\n hyperportalId?: string;\n\n /* deprecated */\n exactAccounting?: boolean;\n\n branches: [Branch, ...Branch[]];\n modules: TenantModule[];\n /**\n * Reports page configuration. `tabs` lists the visible tabs in display order;\n * absent or empty means no reports are configured for the tenant (the page\n * shows a notice instead of tabs).\n */\n reports?: {\n tabs: ReportTabKey[];\n };\n test?: boolean;\n opportunities: {\n types: OpportunityType[];\n };\n crm?: {\n vatNumberRequiredForCompanies?: boolean;\n };\n accounting?: {\n costCenterPerLine?: boolean;\n };\n // E.164 Twilio caller ID used as a fallback when a user has no own number configured\n defaultTwilioPhoneNumber?: string;\n deliveryEmail?: string;\n};\n\nexport type AccountingProvider = 'exact' | 'odoo';\n\nexport type Branch = {\n id: string;\n name: string;\n country: string;\n language: string;\n /* deprecated — use `accounting === 'exact'` instead. Kept until prod cutover. */\n exactAccounting?: boolean;\n accounting?: AccountingProvider;\n currency: string;\n adminNumberPrefix: string;\n stockNumberPrefix: string;\n vatNumber: string;\n contactPerson?: { firstName: string; lastName: string };\n vatRates: {\n standard: string; //percentage value (e.g. 21)\n };\n location: LocationValue;\n\n storecoveExternalId?: number;\n externalQuote?: boolean;\n hyperdmsId?: string;\n internalDealsEnabled?: boolean;\n};\n\nexport type HdmsVehiclesSync = {\n active: boolean;\n};\n\nexport type HdmsCrmSync = {\n active: boolean;\n};\n\nexport type HdmsDocumentSync = {\n active: boolean;\n};\n\nexport type TenantSyncSettings = {\n tenantId: string;\n hdmsVehicles: HdmsVehiclesSync | undefined;\n hdmsCrm: HdmsCrmSync | undefined;\n hdmsDocuments: HdmsDocumentSync | undefined;\n};\n\nexport type WhatsappStateResponse = {\n enabled: boolean;\n};\n"]}
|
package/package.json
CHANGED
|
@@ -189,7 +189,7 @@ export type Opportunity = BaseOpportunity & {
|
|
|
189
189
|
lostReason?: OpportunityLostReasonValues;
|
|
190
190
|
deliveredAt?: string;
|
|
191
191
|
deliveredBy?: string;
|
|
192
|
-
deliveredMode?: 'CMR' | 'Action';
|
|
192
|
+
deliveredMode?: 'CMR' | 'Action' | 'DeliveryConfirmation';
|
|
193
193
|
saleDeliveryTransportEligibleAt?: string;
|
|
194
194
|
status: OpportunityStatus;
|
|
195
195
|
dealStatus?: VehicleSaleDealStatus;
|
|
@@ -551,6 +551,29 @@ export type KanbanOpportunityGroup = {
|
|
|
551
551
|
items: SearchOpportunity[];
|
|
552
552
|
};
|
|
553
553
|
|
|
554
|
+
export type DeliveryConfirmationTemplateData = {
|
|
555
|
+
supplier: {
|
|
556
|
+
company: string;
|
|
557
|
+
contactPerson: string;
|
|
558
|
+
vatNumber?: string;
|
|
559
|
+
};
|
|
560
|
+
customer: {
|
|
561
|
+
company: string;
|
|
562
|
+
contactPerson: string;
|
|
563
|
+
phone?: string;
|
|
564
|
+
};
|
|
565
|
+
vehicle: {
|
|
566
|
+
makeAndModel: string;
|
|
567
|
+
vin: string;
|
|
568
|
+
licensePlate?: string;
|
|
569
|
+
stockNumber?: string;
|
|
570
|
+
};
|
|
571
|
+
opportunity: {
|
|
572
|
+
id: string;
|
|
573
|
+
};
|
|
574
|
+
currentDate: string;
|
|
575
|
+
};
|
|
576
|
+
|
|
554
577
|
export type OpportunitiesKanbanColumn = {
|
|
555
578
|
status: string;
|
|
556
579
|
results: SearchOpportunity[];
|
|
@@ -579,7 +602,13 @@ export type HpLeasingDealRequest = {
|
|
|
579
602
|
vanCourier: boolean;
|
|
580
603
|
newVehicle?: boolean;
|
|
581
604
|
newTrailer?: boolean;
|
|
582
|
-
registrationOnTtcoBe?:
|
|
605
|
+
registrationOnTtcoBe?: boolean;
|
|
606
|
+
externalDelivery?: boolean;
|
|
607
|
+
civilLiabilities?: boolean;
|
|
608
|
+
specialTechnicalInsurance?: boolean;
|
|
609
|
+
allRisks?: boolean;
|
|
610
|
+
roadAssistance?: boolean;
|
|
611
|
+
vabAssistanceVan?: boolean;
|
|
583
612
|
yearOfConstruction?: number;
|
|
584
613
|
chassisnumber?: string;
|
|
585
614
|
vehicleModel?: string;
|
|
@@ -592,6 +621,7 @@ export type HpLeasingDealRequest = {
|
|
|
592
621
|
|
|
593
622
|
company?: string;
|
|
594
623
|
customerNumber?: number; //bisondesk external id
|
|
624
|
+
slbPartner?: string;
|
|
595
625
|
//MrLease fields
|
|
596
626
|
vehicle?: string;
|
|
597
627
|
vehicleNewReferenceMl?: string;
|
package/src/types/quotes.ts
CHANGED
|
@@ -51,6 +51,11 @@ export enum TransportationMode {
|
|
|
51
51
|
ON_LOW_BED = 'onLowBed',
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export enum SelfFinancingType {
|
|
55
|
+
OWN_FINANCING = 'own_financing',
|
|
56
|
+
ALREADY_FINANCED = 'already_financed',
|
|
57
|
+
}
|
|
58
|
+
|
|
54
59
|
type BaseQuoteCalculatorInput = {
|
|
55
60
|
branchId: string;
|
|
56
61
|
branchCountry: string;
|
|
@@ -114,8 +119,12 @@ export type LeasingCalculatorInput = BaseQuoteCalculatorInput & {
|
|
|
114
119
|
salesPrice: string;
|
|
115
120
|
internalDealBranchId?: string;
|
|
116
121
|
} & (
|
|
117
|
-
| { selfFinancing: true; financing?: undefined }
|
|
118
|
-
| {
|
|
122
|
+
| { selfFinancing: true; selfFinancingType?: SelfFinancingType; financing?: undefined }
|
|
123
|
+
| {
|
|
124
|
+
selfFinancing: false;
|
|
125
|
+
selfFinancingType?: undefined;
|
|
126
|
+
financing?: { bankAccountOrganizationId: string; amount: string };
|
|
127
|
+
}
|
|
119
128
|
);
|
|
120
129
|
taxes: {
|
|
121
130
|
yearlyRoadTax: boolean;
|
|
@@ -95,7 +95,7 @@ export type LeasingCumulativeBucket = {
|
|
|
95
95
|
export type LeasingOverdueBucket = {
|
|
96
96
|
/** `YYYY-MM` month. */
|
|
97
97
|
month: string;
|
|
98
|
-
/** Overdue rent amount (excl VAT) as of
|
|
98
|
+
/** Overdue rent amount (excl VAT) as of that month's snapshot (see `overdueHistoryDay`). */
|
|
99
99
|
amount: number;
|
|
100
100
|
};
|
|
101
101
|
|
|
@@ -169,17 +169,30 @@ export type LeasingReportResponse = {
|
|
|
169
169
|
// Client risk, as of the snapshot month. `riskLevel` is zero-inflated (most clients
|
|
170
170
|
// are 0), so this is the at-risk tail shape, not a central statistic.
|
|
171
171
|
risk: {
|
|
172
|
-
/**
|
|
172
|
+
/**
|
|
173
|
+
* Active-contract clients at risk level ≥ 2, with YoY. Level 1 (one overdue invoice
|
|
174
|
+
* per overdue contract) is the ordinary pays-next-month case and isn't counted, so
|
|
175
|
+
* this can be lower than the sum of `bands` (which still includes level 1).
|
|
176
|
+
* For in-progress periods (mtd/ytd) `prev`/`pct` are null: the risk history stores
|
|
177
|
+
* month-end states only, so a mid-month reading has no day-aligned year-ago base.
|
|
178
|
+
*/
|
|
173
179
|
clientsAtRisk: YoyMetric;
|
|
174
180
|
/** Total active-contract clients (the at-risk denominator). */
|
|
175
181
|
activeClients: number;
|
|
176
|
-
/** Severity-band counts of
|
|
182
|
+
/** Severity-band counts of all overdue clients (`riskLevel` floored: levels 1/2/3/4+). */
|
|
177
183
|
bands: { band: string; count: number }[];
|
|
178
184
|
};
|
|
179
185
|
/** Fixed 12-month cumulative new contracts, this calendar year vs last. */
|
|
180
186
|
cumulativeContracts: LeasingCumulativeBucket[];
|
|
181
|
-
/** Fixed trailing-6-month overdue rent amount (excl VAT),
|
|
187
|
+
/** Fixed trailing-6-month overdue rent amount (excl VAT), one snapshot per month. */
|
|
182
188
|
overdueHistory: LeasingOverdueBucket[];
|
|
189
|
+
/**
|
|
190
|
+
* Day-of-month the overdue-history snapshots are taken on — today's day, so every past
|
|
191
|
+
* month is measured at the same point in its month as the in-progress one. Null when
|
|
192
|
+
* today is past the 28th (a day not every month has) and the snapshots are month-ends
|
|
193
|
+
* instead, with the current month at now.
|
|
194
|
+
*/
|
|
195
|
+
overdueHistoryDay: number | null;
|
|
183
196
|
/** Net invoiced rent (excl VAT) by issue month, from a fixed start (Jan 2025) to now. */
|
|
184
197
|
invoicedHistory: LeasingInvoicedBucket[];
|
|
185
198
|
/** Track-and-trace fleet usage over the window. */
|
|
@@ -81,6 +81,18 @@ export type SalesReportMake = {
|
|
|
81
81
|
yoyPct: number | null;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
/** A ranked organization row for the top-clients / top-suppliers cards. */
|
|
85
|
+
export type SalesReportTopOrg = {
|
|
86
|
+
/** Organization id (`org.id` for clients; `purchase.organizationId` for suppliers). */
|
|
87
|
+
id: string;
|
|
88
|
+
/** Organization name (resolved server-side); falls back to the id when missing. */
|
|
89
|
+
name: string;
|
|
90
|
+
/** The org's ISO country code (lowercase); null when not recorded. */
|
|
91
|
+
countryCode: string | null;
|
|
92
|
+
units: number;
|
|
93
|
+
yoyPct: number | null;
|
|
94
|
+
};
|
|
95
|
+
|
|
84
96
|
/** A conglomerate-flagged organization (there is no group/parent model — each org stands alone). */
|
|
85
97
|
export type SalesReportConglomerateOrg = {
|
|
86
98
|
/** `org.id`. */
|
|
@@ -157,6 +169,10 @@ export type SalesReportResponse = {
|
|
|
157
169
|
salespeople: SalesReportSalesperson[];
|
|
158
170
|
/** All purchasers with vehicles bought in the current window (capped; the client list scrolls). */
|
|
159
171
|
buyers: SalesReportBuyer[];
|
|
172
|
+
/** Top client organizations by units bought from us in the current window. */
|
|
173
|
+
topClients: SalesReportTopOrg[];
|
|
174
|
+
/** Top supplier organizations by used vehicles purchased from them in the current window. */
|
|
175
|
+
topSuppliers: SalesReportTopOrg[];
|
|
160
176
|
/** Returning-customer tenure shares (4 buckets). */
|
|
161
177
|
returning: TenureBucket[];
|
|
162
178
|
conglomerate: SalesReportConglomerate;
|
package/src/types/tenants.ts
CHANGED
|
@@ -32,11 +32,17 @@ export enum TenantModule {
|
|
|
32
32
|
Bootstrap = 'bootstrap',
|
|
33
33
|
WhatsappNotifications = 'whatsapp_notifications',
|
|
34
34
|
Hexon = 'hexon',
|
|
35
|
+
DeliveryConfirmation = 'delivery_confirmation',
|
|
35
36
|
Transport = 'transport',
|
|
36
37
|
Reports = 'reports',
|
|
37
38
|
Prospects = 'prospects',
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
/** Report tabs a tenant can enable, in canonical order. */
|
|
42
|
+
export const REPORT_TAB_KEYS = ['sales', 'leasing', 'purchases'] as const;
|
|
43
|
+
|
|
44
|
+
export type ReportTabKey = (typeof REPORT_TAB_KEYS)[number];
|
|
45
|
+
|
|
40
46
|
export type Tenant = PublicTenant & {
|
|
41
47
|
cognito?: CognitoInfo;
|
|
42
48
|
languages: [string, ...string[]];
|
|
@@ -50,6 +56,14 @@ export type Tenant = PublicTenant & {
|
|
|
50
56
|
|
|
51
57
|
branches: [Branch, ...Branch[]];
|
|
52
58
|
modules: TenantModule[];
|
|
59
|
+
/**
|
|
60
|
+
* Reports page configuration. `tabs` lists the visible tabs in display order;
|
|
61
|
+
* absent or empty means no reports are configured for the tenant (the page
|
|
62
|
+
* shows a notice instead of tabs).
|
|
63
|
+
*/
|
|
64
|
+
reports?: {
|
|
65
|
+
tabs: ReportTabKey[];
|
|
66
|
+
};
|
|
53
67
|
test?: boolean;
|
|
54
68
|
opportunities: {
|
|
55
69
|
types: OpportunityType[];
|
|
@@ -62,6 +76,7 @@ export type Tenant = PublicTenant & {
|
|
|
62
76
|
};
|
|
63
77
|
// E.164 Twilio caller ID used as a fallback when a user has no own number configured
|
|
64
78
|
defaultTwilioPhoneNumber?: string;
|
|
79
|
+
deliveryEmail?: string;
|
|
65
80
|
};
|
|
66
81
|
|
|
67
82
|
export type AccountingProvider = 'exact' | 'odoo';
|