@bisondesk/core-sdk 1.0.681 → 1.0.683
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/leasing-debtors.d.ts +3 -0
- package/lib/types/leasing-debtors.d.ts.map +1 -1
- package/lib/types/leasing-debtors.js.map +1 -1
- package/lib/types/leasing-search.d.ts +2 -0
- package/lib/types/leasing-search.d.ts.map +1 -1
- package/lib/types/leasing-search.js.map +1 -1
- package/lib/types/mileage.d.ts +38 -0
- package/lib/types/mileage.d.ts.map +1 -0
- package/lib/types/mileage.js +15 -0
- package/lib/types/mileage.js.map +1 -0
- package/lib/utils/mileage.d.ts +18 -0
- package/lib/utils/mileage.d.ts.map +1 -0
- package/lib/utils/mileage.js +70 -0
- package/lib/utils/mileage.js.map +1 -0
- package/lib/utils/mileage.test.d.ts +2 -0
- package/lib/utils/mileage.test.d.ts.map +1 -0
- package/lib/utils/mileage.test.js +103 -0
- package/lib/utils/mileage.test.js.map +1 -0
- package/package.json +1 -1
- package/src/types/leasing-debtors.ts +4 -0
- package/src/types/leasing-search.ts +2 -0
- package/src/types/mileage.ts +51 -0
- package/src/utils/mileage.test.ts +151 -0
- package/src/utils/mileage.ts +111 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/types/activities.js +0 -13
- package/src/types/activities.js.map +0 -1
- package/src/types/comparables.js +0 -2
- package/src/types/comparables.js.map +0 -1
- package/src/types/crm.js +0 -58
- package/src/types/crm.js.map +0 -1
- package/src/types/dashboard.js +0 -2
- package/src/types/dashboard.js.map +0 -1
- package/src/types/definitions.js +0 -2
- package/src/types/definitions.js.map +0 -1
- package/src/types/fields.js +0 -2
- package/src/types/fields.js.map +0 -1
- package/src/types/insights.js +0 -2
- package/src/types/insights.js.map +0 -1
- package/src/types/interests.js +0 -6
- package/src/types/interests.js.map +0 -1
- package/src/types/internal-events.js +0 -18
- package/src/types/internal-events.js.map +0 -1
- package/src/types/internet-opportunities.js +0 -2
- package/src/types/internet-opportunities.js.map +0 -1
- package/src/types/internet-vehicles.js +0 -2
- package/src/types/internet-vehicles.js.map +0 -1
- package/src/types/leasing-administration.js +0 -2
- package/src/types/leasing-administration.js.map +0 -1
- package/src/types/leasing-debtors.js +0 -2
- package/src/types/leasing-debtors.js.map +0 -1
- package/src/types/leasing-search.js +0 -2
- package/src/types/leasing-search.js.map +0 -1
- package/src/types/leasing-settings.js +0 -7
- package/src/types/leasing-settings.js.map +0 -1
- package/src/types/leasing.js +0 -38
- package/src/types/leasing.js.map +0 -1
- package/src/types/marketing.js +0 -35
- package/src/types/marketing.js.map +0 -1
- package/src/types/offers.js +0 -56
- package/src/types/opportunities.js +0 -107
- package/src/types/opportunities.js.map +0 -1
- package/src/types/payments.js +0 -7
- package/src/types/picklists.js +0 -2
- package/src/types/picklists.js.map +0 -1
- package/src/types/quotes.js +0 -42
- package/src/types/recently-viewed.js +0 -2
- package/src/types/recently-viewed.js.map +0 -1
- package/src/types/reservations.js +0 -5
- package/src/types/reservations.js.map +0 -1
- package/src/types/roi-ratings.js +0 -5
- package/src/types/roi-ratings.js.map +0 -1
- package/src/types/saved-filters.js +0 -9
- package/src/types/saved-filters.js.map +0 -1
- package/src/types/search.js +0 -2
- package/src/types/search.js.map +0 -1
- package/src/types/settings.js +0 -2
- package/src/types/settings.js.map +0 -1
- package/src/types/templates.js +0 -2
- package/src/types/templates.js.map +0 -1
- package/src/types/tenants.js +0 -21
- package/src/types/tenants.js.map +0 -1
- package/src/types/user-performance.js +0 -7
- package/src/types/user-performance.js.map +0 -1
- package/src/types/utils.js +0 -2
- package/src/types/validation.js +0 -2
- package/src/types/validation.js.map +0 -1
- package/src/types/vehicle-sales.js +0 -6
- package/src/types/vehicle-sales.js.map +0 -1
- package/src/types/vehicles.js +0 -98
- package/src/types/vehicles.js.map +0 -1
- package/src/utils/leasing.js +0 -6
- package/src/utils/leasing.js.map +0 -1
- package/src/utils/opportunities.js +0 -48
- package/src/utils/opportunities.js.map +0 -1
|
@@ -2,6 +2,7 @@ import { EmailMessage } from '@bisondesk/commons-sdk/messages';
|
|
|
2
2
|
import { NextList, PaginatedList } from '@bisondesk/commons-sdk/types';
|
|
3
3
|
import { Contact, Organization } from './crm.js';
|
|
4
4
|
import { LeasingContract } from './leasing.js';
|
|
5
|
+
import { ContractMileage, MileageSummary } from './mileage.js';
|
|
5
6
|
import { BaseSearchRequest, SortFilter, SortOrder } from './search.js';
|
|
6
7
|
import { DataRecord, ReferenceData } from './utils.js';
|
|
7
8
|
export type MonthData = {
|
|
@@ -257,6 +258,8 @@ export type SearchDebtorsDossier = {
|
|
|
257
258
|
remindersSent: number;
|
|
258
259
|
hasActiveLdrs?: boolean;
|
|
259
260
|
};
|
|
261
|
+
mileage?: ContractMileage[];
|
|
262
|
+
mileageSummary?: MileageSummary;
|
|
260
263
|
};
|
|
261
264
|
export type DebtorsDossierKanbanColumn = {
|
|
262
265
|
status: DebtorsDossierStatus;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leasing-debtors.d.ts","sourceRoot":"/","sources":["types/leasing-debtors.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"leasing-debtors.d.ts","sourceRoot":"/","sources":["types/leasing-debtors.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leasing-debtors.js","sourceRoot":"/","sources":["types/leasing-debtors.ts"],"names":[],"mappings":"AAsDA,MAAM,CAAN,IAAY,oBAQX;AARD,WAAY,oBAAoB;IAC9B,uDAA+B,CAAA;IAC/B,2CAAmB,CAAA;IACnB,+DAAuC,CAAA;IACvC,6CAAqB,CAAA;IACrB,yDAAiC,CAAA;IACjC,2CAAmB,CAAA;IACnB,6CAAqB,CAAA;AACvB,CAAC,EARW,oBAAoB,KAApB,oBAAoB,QAQ/B;AAED,MAAM,CAAC,MAAM,kCAAkC,GAG3C;IACF,CAAC,oBAAoB,CAAC,aAAa,CAAC,EAAE,IAAI;IAC1C,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE;IAC1E,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE;IACxF,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE;IAC7E,CAAC,oBAAoB,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,EAAE;IAC3F,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE;IAC7E,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE;CACzE,CAAC;AA6CF,MAAM,CAAN,IAAY,qBAQX;AARD,WAAY,qBAAqB;IAC/B,sDAA6B,CAAA;IAC7B,sDAA6B,CAAA;IAC7B,0CAAiB,CAAA;IACjB,wDAA+B,CAAA;IAC/B,8DAAqC,CAAA;IACrC,gEAAuC,CAAA;IACvC,0CAAiB,CAAA;AACnB,CAAC,EARW,qBAAqB,KAArB,qBAAqB,QAQhC;AAyHD,MAAM,CAAN,IAAY,kBAYX;AAZD,WAAY,kBAAkB;IAC5B,+CAAyB,CAAA;IACzB,2DAAqC,CAAA;IACrC,uDAAiC,CAAA;IACjC,qCAAe,CAAA;IACf,2CAAqB,CAAA;IACrB,2CAAqB,CAAA;IACrB,iDAA2B,CAAA;IAC3B,+CAAyB,CAAA;IACzB,2DAAqC,CAAA;IACrC,mEAA6C,CAAA;IAC7C,yCAAmB,CAAA;AACrB,CAAC,EAZW,kBAAkB,KAAlB,kBAAkB,QAY7B;AAkHD,MAAM,CAAC,MAAM,yBAAyB,GAA2B;IAC/D,oBAAoB,CAAC,aAAa;IAClC,oBAAoB,CAAC,OAAO;IAC5B,oBAAoB,CAAC,iBAAiB;IACtC,oBAAoB,CAAC,QAAQ;IAC7B,oBAAoB,CAAC,cAAc;IACnC,oBAAoB,CAAC,OAAO;CAC7B,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,oBAAoB,CAAC,QAAQ,CAAC;AAEvE,MAAM,CAAC,MAAM,8BAA8B,GAA2B;IACpE,oBAAoB,CAAC,QAAQ;CAC9B,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,GAAG,yBAAyB;IAC5B,GAAG,8BAA8B;CAClC,CAAC","sourcesContent":["import { EmailMessage } from '@bisondesk/commons-sdk/messages';\nimport { NextList, PaginatedList } from '@bisondesk/commons-sdk/types';\nimport { Contact, Organization } from './crm.js';\nimport { LeasingContract } from './leasing.js';\nimport { BaseSearchRequest, SortFilter, SortOrder } from './search.js';\nimport { DataRecord, ReferenceData } from './utils.js';\n\nexport type MonthData = {\n activeContractIds: string[];\n date: string; // YYYY-MM\n overdueAmount: string;\n unpaidAmount: string;\n overdueContractIds: string[];\n overdueInvoiceIds: string[];\n riskLevel: number;\n monthlyInvoicedAmount: string;\n // Non-leasing (\"extra\") debt for this month, computed as-of month-end.\n nonLeasingOverdueAmount: string;\n nonLeasingUnpaidAmount: string;\n};\n\nexport type DebtorInfo = {\n clientId: string;\n branchIds: string[];\n months: MonthData[];\n\n // properties related to the current month\n activeContracts: number;\n overdueAmount: string;\n nonLeasingOverdueAmount: string;\n nonLeasingUnpaidAmount: string;\n unpaidAmount: string;\n overdueContracts: number;\n riskLevel: number;\n monthlyInvoicedAmount: string;\n};\n\nexport type SearchDebtorInfo = {\n org: Organization;\n contact?: Contact;\n debtor: DebtorInfo;\n activeDebtorDossier?: {\n dossier: DebtorsDossier;\n hasDossier: boolean;\n lastActivityAt?: string;\n lastActivityBy?: string;\n hasActivitiesLogged: boolean;\n };\n custom: {\n riskLevelLabel: string;\n hasActiveContracts: boolean;\n };\n};\n\nexport enum DebtorsDossierStatus {\n AUTO_REMINDER = 'auto_reminder',\n OVERDUE = 'overdue',\n CONTACT_ATTEMPTED = 'contact_attempted',\n DIALOGUE = 'dialogue',\n PROMISE_TO_PAY = 'promise_to_pay',\n FAILURE = 'failure',\n RESOLVED = 'resolved',\n}\n\nexport const debtorsDossierStatusToDateFieldMap: Record<\n DebtorsDossierStatus,\n { date: keyof DossierStatusLogFields; author: keyof DossierStatusLogFields } | null\n> = {\n [DebtorsDossierStatus.AUTO_REMINDER]: null,\n [DebtorsDossierStatus.OVERDUE]: { date: 'overdueAt', author: 'overdueBy' },\n [DebtorsDossierStatus.CONTACT_ATTEMPTED]: { date: 'contactedAt', author: 'contactedBy' },\n [DebtorsDossierStatus.DIALOGUE]: { date: 'dialogueAt', author: 'dialogueBy' },\n [DebtorsDossierStatus.PROMISE_TO_PAY]: { date: 'promiseToPayAt', author: 'promiseToPayBy' },\n [DebtorsDossierStatus.RESOLVED]: { date: 'resolvedAt', author: 'resolvedBy' },\n [DebtorsDossierStatus.FAILURE]: { date: 'failedAt', author: 'failedBy' },\n};\n\n/******\n * Auto Follow-Up Types\n ******/\n\nexport type ReminderWhatsappAttemptStatus = 'SENT' | 'DELIVERED' | 'FAILED' | 'SKIPPED';\n\n// see docs/adr/0026-whatsapp-leasing-notifications-alongside-email.md\nexport type ReminderWhatsappAttempt = {\n dedupId: string;\n templateId: string;\n phone: string;\n riskLevel: number;\n sentAt: string;\n status: ReminderWhatsappAttemptStatus;\n failureReason?: string;\n};\n\nexport type DebtorAutoFollowUp = {\n id: string;\n organizationId: string;\n organizationName: string;\n status: 'ONGOING' | 'ERROR' | 'SUCCESS' | 'EXPIRED' | 'DISCARDED';\n discardReason?: string;\n emails: EmailMessage[];\n whatsapps?: ReminderWhatsappAttempt[];\n createdAt: string;\n modifiedAt: string;\n completedAt?: string;\n nextActionAt: string;\n riskLevel: number;\n};\n\nexport type ListOverdueRemindersResponse = PaginatedList<DebtorAutoFollowUp, ReferenceData>;\nexport type ListOverdueRemindersRequest = {\n offset: number;\n limit: number;\n sortBy: SortFilter;\n};\n\n/******\n * Debtor Dossier Types\n ******/\n\nexport enum DebtorsDossierActions {\n SET_METADATA = 'set_metadata',\n ADD_ACTIVITY = 'add_activity',\n FINISH = 'finish',\n SET_DOCUMENTS = 'set_documents',\n SET_PAYMENT_PLAN = 'set_payment_plan',\n SET_LEGAL_DOSSIER = 'set_legal_dossier',\n REOPEN = 'reopen',\n}\n\nexport type DossierStatusLogFields = {\n failedAt?: string;\n failedBy?: string;\n resolvedAt?: string;\n contactedAt?: string;\n contactedBy?: string;\n overdueAt?: string;\n overdueBy?: string;\n resolvedBy?: string;\n dialogueAt?: string;\n dialogueBy?: string;\n promiseToPayAt?: string;\n promiseToPayBy?: string;\n};\n\nexport type BaseDebtorsDossier = {\n organizationId: string;\n tags: string[];\n origin: 'manual' | 'auto';\n autoFollowUpId?: string;\n administrativeUserId?: string;\n branchId: string;\n tenantId: string;\n};\nexport type DebtorsDossierStatusAudit = {\n from: DebtorsDossierStatus;\n to: DebtorsDossierStatus;\n changedAt: string;\n changedBy: string;\n};\n\nexport type DebtorsDossier = BaseDebtorsDossier &\n DossierStatusLogFields & {\n id: string;\n createdAt: string;\n createdBy: string;\n updatedAt: string;\n updatedBy: string;\n status: DebtorsDossierStatus;\n statusAudit: DebtorsDossierStatusAudit[];\n };\n\nexport type NewDebtorsDossier = BaseDebtorsDossier & {\n id?: undefined;\n createdBy?: undefined;\n createdAt?: undefined;\n updatedBy?: undefined;\n updatedAt?: undefined;\n};\n\nexport type DebtorsDossierBff = {\n dossier: DataRecord<DebtorsDossier>;\n organization?: Organization;\n leasingContracts: LeasingContract[];\n debt?: DebtorInfo;\n paymentPlan?: DebtorsPaymentPlan;\n legalDossier?: LegalDossier;\n trackAndTraceDevices: {\n /* odometer: TrackAndTraceOdometerData;\n device: TrackAndTraceDevice; */\n }[];\n};\n\nexport type UpdateDebtorsDossier = Partial<\n Pick<DebtorsDossier, 'status' | 'tags' | 'branchId' | 'organizationId'>\n> & {\n overdue?: boolean;\n resolve?: boolean;\n administrativeUserId?: string | null;\n};\n\n/******\n * Payment Plan Types\n ******/\n\nexport type DebtorsPaymentPlan = {\n id: string;\n debtorDossierId: string;\n\n notes: {\n content: string;\n createdAt: string;\n createdBy: string;\n }[];\n\n reminders?: {\n startDate: string; // ISO date string\n frequency: {\n every: number;\n period: 'days' | 'weeks' | 'months';\n };\n endCondition:\n | {\n endDate: string; // ISO date string\n }\n | {\n occurrences: number; // Number of reminders to send\n };\n };\n\n createdAt: string;\n createdBy: string;\n updatedAt: string;\n updatedBy: string;\n};\n\nexport type NewPaymentPlan = Omit<\n DebtorsPaymentPlan,\n 'id' | 'createdAt' | 'updatedAt' | 'createdBy' | 'updatedBy' | 'notes'\n> & { notes?: string };\n\nexport type UpdatePaymentPlan = Partial<Pick<DebtorsPaymentPlan, 'reminders'>> & {\n newNote?: string;\n};\n\n/******\n * Legal Dossier Types\n ******/\n\nexport enum LegalDossierStatus {\n ASSESSMENT = 'assessment',\n PRE_LEGAL_NOTICE = 'pre_legal_notice',\n SENT_TO_LAWYER = 'sent_to_lawyer',\n FILED = 'filed',\n IN_COURT = 'in_court',\n JUDGMENT = 'judgment',\n ENFORCEMENT = 'enforcement',\n SETTLEMENT = 'settlement',\n CLOSED_RECOVERED = 'closed_recovered',\n CLOSED_UNRECOVERABLE = 'closed_unrecoverable',\n ON_HOLD = 'on_hold',\n}\n\nexport type LegalDossier = {\n id: string;\n debtorDossierId: string;\n caseNumber?: string;\n courtDate?: string; // ISO date string (YYYY-MM-DD)\n vehicleReportedToPolice?: boolean;\n vehicleReportedToPoliceAt?: string; // ISO timestamp, stamped server-side\n notes?: string;\n createdAt: string;\n createdBy: string;\n updatedAt: string;\n updatedBy: string;\n status: LegalDossierStatus;\n};\n\nexport type NewLegalDossier = Omit<\n LegalDossier,\n 'id' | 'createdAt' | 'updatedAt' | 'createdBy' | 'updatedBy'\n>;\n\nexport type UpdateLegalDossier = Partial<\n Pick<LegalDossier, 'caseNumber' | 'courtDate' | 'status' | 'notes' | 'vehicleReportedToPolice'>\n>;\n\n/******\n * Debtor Dossier Events\n ******/\n\nexport type DebtorsDossierCreateEvent = {\n action: 'created';\n data: DebtorsDossier;\n previousData?: undefined;\n tenantId: string;\n userId: string;\n};\n\nexport type DebtorsDossierUpdateEvent = {\n action: 'updated';\n data: DebtorsDossier;\n previousData: DebtorsDossier;\n tenantId: string;\n userId: string;\n};\n\nexport type DebtorsDossierDeleteEvent = {\n action: 'deleted';\n data?: undefined;\n previousData: DebtorsDossier;\n tenantId: string;\n userId: string;\n};\n\nexport type DebtorsDossierEvent =\n | DebtorsDossierCreateEvent\n | DebtorsDossierUpdateEvent\n | DebtorsDossierDeleteEvent;\n\n/************\n *\n * Search\n */\n\nexport type SearchDebtorsDossier = {\n contact?: Contact;\n debtorsDossier: DebtorsDossier;\n org?: Organization;\n legalDossier?: LegalDossier;\n paymentPlan?: DebtorsPaymentPlan;\n hasPaymentPlan?: boolean;\n branchIds?: string[];\n tasks: {\n totalTasks: number;\n openTasks: number;\n nextDueAt?: string;\n };\n overdue: {\n riskLevel: number;\n riskLevelLabel?: string;\n remindersSent: number;\n hasActiveLdrs?: boolean;\n };\n};\n\n/************\n *\n * Kanban\n */\n\nexport type DebtorsDossierKanbanColumn = {\n status: DebtorsDossierStatus;\n results: SearchDebtorsDossier[];\n totalCount: number;\n totalValue: string;\n};\n\nexport type MSearchDebtorsDossierKanbanColumn = {\n column: DebtorsDossierKanbanColumn;\n nextToken?: string;\n};\n\nexport type KanbanDebtorsDossierSearchRequest = BaseSearchRequest & {\n nextTokens?: Record<string, string | undefined>;\n statusSortBy?: Record<DebtorsDossierStatus, { fieldId: string; order: SortOrder }[]>;\n};\n\nexport type KanbanDebtorsDossierNextList = Omit<\n NextList<DebtorsDossierKanbanColumn, ReferenceData>,\n 'nextToken'\n> & {\n nextTokens?: Record<string, string | undefined>;\n};\n\nexport const DebtorsDossierStatusOrder: DebtorsDossierStatus[] = [\n DebtorsDossierStatus.AUTO_REMINDER,\n DebtorsDossierStatus.OVERDUE,\n DebtorsDossierStatus.CONTACT_ATTEMPTED,\n DebtorsDossierStatus.DIALOGUE,\n DebtorsDossierStatus.PROMISE_TO_PAY,\n DebtorsDossierStatus.FAILURE,\n];\n\nexport const DebtorsDossierWonColumnId = DebtorsDossierStatus.RESOLVED;\n\nexport const DebtorsDossierKanbanEndColumns: DebtorsDossierStatus[] = [\n DebtorsDossierStatus.RESOLVED,\n];\n\nexport const DebtorsDossierKanbanColumns = [\n ...DebtorsDossierStatusOrder,\n ...DebtorsDossierKanbanEndColumns,\n];\n"]}
|
|
1
|
+
{"version":3,"file":"leasing-debtors.js","sourceRoot":"/","sources":["types/leasing-debtors.ts"],"names":[],"mappings":"AAuDA,MAAM,CAAN,IAAY,oBAQX;AARD,WAAY,oBAAoB;IAC9B,uDAA+B,CAAA;IAC/B,2CAAmB,CAAA;IACnB,+DAAuC,CAAA;IACvC,6CAAqB,CAAA;IACrB,yDAAiC,CAAA;IACjC,2CAAmB,CAAA;IACnB,6CAAqB,CAAA;AACvB,CAAC,EARW,oBAAoB,KAApB,oBAAoB,QAQ/B;AAED,MAAM,CAAC,MAAM,kCAAkC,GAG3C;IACF,CAAC,oBAAoB,CAAC,aAAa,CAAC,EAAE,IAAI;IAC1C,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE;IAC1E,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE;IACxF,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE;IAC7E,CAAC,oBAAoB,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,EAAE;IAC3F,CAAC,oBAAoB,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE;IAC7E,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE;CACzE,CAAC;AA6CF,MAAM,CAAN,IAAY,qBAQX;AARD,WAAY,qBAAqB;IAC/B,sDAA6B,CAAA;IAC7B,sDAA6B,CAAA;IAC7B,0CAAiB,CAAA;IACjB,wDAA+B,CAAA;IAC/B,8DAAqC,CAAA;IACrC,gEAAuC,CAAA;IACvC,0CAAiB,CAAA;AACnB,CAAC,EARW,qBAAqB,KAArB,qBAAqB,QAQhC;AAyHD,MAAM,CAAN,IAAY,kBAYX;AAZD,WAAY,kBAAkB;IAC5B,+CAAyB,CAAA;IACzB,2DAAqC,CAAA;IACrC,uDAAiC,CAAA;IACjC,qCAAe,CAAA;IACf,2CAAqB,CAAA;IACrB,2CAAqB,CAAA;IACrB,iDAA2B,CAAA;IAC3B,+CAAyB,CAAA;IACzB,2DAAqC,CAAA;IACrC,mEAA6C,CAAA;IAC7C,yCAAmB,CAAA;AACrB,CAAC,EAZW,kBAAkB,KAAlB,kBAAkB,QAY7B;AAqHD,MAAM,CAAC,MAAM,yBAAyB,GAA2B;IAC/D,oBAAoB,CAAC,aAAa;IAClC,oBAAoB,CAAC,OAAO;IAC5B,oBAAoB,CAAC,iBAAiB;IACtC,oBAAoB,CAAC,QAAQ;IAC7B,oBAAoB,CAAC,cAAc;IACnC,oBAAoB,CAAC,OAAO;CAC7B,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,oBAAoB,CAAC,QAAQ,CAAC;AAEvE,MAAM,CAAC,MAAM,8BAA8B,GAA2B;IACpE,oBAAoB,CAAC,QAAQ;CAC9B,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,GAAG,yBAAyB;IAC5B,GAAG,8BAA8B;CAClC,CAAC","sourcesContent":["import { EmailMessage } from '@bisondesk/commons-sdk/messages';\nimport { NextList, PaginatedList } from '@bisondesk/commons-sdk/types';\nimport { Contact, Organization } from './crm.js';\nimport { LeasingContract } from './leasing.js';\nimport { ContractMileage, MileageSummary } from './mileage.js';\nimport { BaseSearchRequest, SortFilter, SortOrder } from './search.js';\nimport { DataRecord, ReferenceData } from './utils.js';\n\nexport type MonthData = {\n activeContractIds: string[];\n date: string; // YYYY-MM\n overdueAmount: string;\n unpaidAmount: string;\n overdueContractIds: string[];\n overdueInvoiceIds: string[];\n riskLevel: number;\n monthlyInvoicedAmount: string;\n // Non-leasing (\"extra\") debt for this month, computed as-of month-end.\n nonLeasingOverdueAmount: string;\n nonLeasingUnpaidAmount: string;\n};\n\nexport type DebtorInfo = {\n clientId: string;\n branchIds: string[];\n months: MonthData[];\n\n // properties related to the current month\n activeContracts: number;\n overdueAmount: string;\n nonLeasingOverdueAmount: string;\n nonLeasingUnpaidAmount: string;\n unpaidAmount: string;\n overdueContracts: number;\n riskLevel: number;\n monthlyInvoicedAmount: string;\n};\n\nexport type SearchDebtorInfo = {\n org: Organization;\n contact?: Contact;\n debtor: DebtorInfo;\n activeDebtorDossier?: {\n dossier: DebtorsDossier;\n hasDossier: boolean;\n lastActivityAt?: string;\n lastActivityBy?: string;\n hasActivitiesLogged: boolean;\n };\n custom: {\n riskLevelLabel: string;\n hasActiveContracts: boolean;\n };\n};\n\nexport enum DebtorsDossierStatus {\n AUTO_REMINDER = 'auto_reminder',\n OVERDUE = 'overdue',\n CONTACT_ATTEMPTED = 'contact_attempted',\n DIALOGUE = 'dialogue',\n PROMISE_TO_PAY = 'promise_to_pay',\n FAILURE = 'failure',\n RESOLVED = 'resolved',\n}\n\nexport const debtorsDossierStatusToDateFieldMap: Record<\n DebtorsDossierStatus,\n { date: keyof DossierStatusLogFields; author: keyof DossierStatusLogFields } | null\n> = {\n [DebtorsDossierStatus.AUTO_REMINDER]: null,\n [DebtorsDossierStatus.OVERDUE]: { date: 'overdueAt', author: 'overdueBy' },\n [DebtorsDossierStatus.CONTACT_ATTEMPTED]: { date: 'contactedAt', author: 'contactedBy' },\n [DebtorsDossierStatus.DIALOGUE]: { date: 'dialogueAt', author: 'dialogueBy' },\n [DebtorsDossierStatus.PROMISE_TO_PAY]: { date: 'promiseToPayAt', author: 'promiseToPayBy' },\n [DebtorsDossierStatus.RESOLVED]: { date: 'resolvedAt', author: 'resolvedBy' },\n [DebtorsDossierStatus.FAILURE]: { date: 'failedAt', author: 'failedBy' },\n};\n\n/******\n * Auto Follow-Up Types\n ******/\n\nexport type ReminderWhatsappAttemptStatus = 'SENT' | 'DELIVERED' | 'FAILED' | 'SKIPPED';\n\n// see docs/adr/0026-whatsapp-leasing-notifications-alongside-email.md\nexport type ReminderWhatsappAttempt = {\n dedupId: string;\n templateId: string;\n phone: string;\n riskLevel: number;\n sentAt: string;\n status: ReminderWhatsappAttemptStatus;\n failureReason?: string;\n};\n\nexport type DebtorAutoFollowUp = {\n id: string;\n organizationId: string;\n organizationName: string;\n status: 'ONGOING' | 'ERROR' | 'SUCCESS' | 'EXPIRED' | 'DISCARDED';\n discardReason?: string;\n emails: EmailMessage[];\n whatsapps?: ReminderWhatsappAttempt[];\n createdAt: string;\n modifiedAt: string;\n completedAt?: string;\n nextActionAt: string;\n riskLevel: number;\n};\n\nexport type ListOverdueRemindersResponse = PaginatedList<DebtorAutoFollowUp, ReferenceData>;\nexport type ListOverdueRemindersRequest = {\n offset: number;\n limit: number;\n sortBy: SortFilter;\n};\n\n/******\n * Debtor Dossier Types\n ******/\n\nexport enum DebtorsDossierActions {\n SET_METADATA = 'set_metadata',\n ADD_ACTIVITY = 'add_activity',\n FINISH = 'finish',\n SET_DOCUMENTS = 'set_documents',\n SET_PAYMENT_PLAN = 'set_payment_plan',\n SET_LEGAL_DOSSIER = 'set_legal_dossier',\n REOPEN = 'reopen',\n}\n\nexport type DossierStatusLogFields = {\n failedAt?: string;\n failedBy?: string;\n resolvedAt?: string;\n contactedAt?: string;\n contactedBy?: string;\n overdueAt?: string;\n overdueBy?: string;\n resolvedBy?: string;\n dialogueAt?: string;\n dialogueBy?: string;\n promiseToPayAt?: string;\n promiseToPayBy?: string;\n};\n\nexport type BaseDebtorsDossier = {\n organizationId: string;\n tags: string[];\n origin: 'manual' | 'auto';\n autoFollowUpId?: string;\n administrativeUserId?: string;\n branchId: string;\n tenantId: string;\n};\nexport type DebtorsDossierStatusAudit = {\n from: DebtorsDossierStatus;\n to: DebtorsDossierStatus;\n changedAt: string;\n changedBy: string;\n};\n\nexport type DebtorsDossier = BaseDebtorsDossier &\n DossierStatusLogFields & {\n id: string;\n createdAt: string;\n createdBy: string;\n updatedAt: string;\n updatedBy: string;\n status: DebtorsDossierStatus;\n statusAudit: DebtorsDossierStatusAudit[];\n };\n\nexport type NewDebtorsDossier = BaseDebtorsDossier & {\n id?: undefined;\n createdBy?: undefined;\n createdAt?: undefined;\n updatedBy?: undefined;\n updatedAt?: undefined;\n};\n\nexport type DebtorsDossierBff = {\n dossier: DataRecord<DebtorsDossier>;\n organization?: Organization;\n leasingContracts: LeasingContract[];\n debt?: DebtorInfo;\n paymentPlan?: DebtorsPaymentPlan;\n legalDossier?: LegalDossier;\n trackAndTraceDevices: {\n /* odometer: TrackAndTraceOdometerData;\n device: TrackAndTraceDevice; */\n }[];\n};\n\nexport type UpdateDebtorsDossier = Partial<\n Pick<DebtorsDossier, 'status' | 'tags' | 'branchId' | 'organizationId'>\n> & {\n overdue?: boolean;\n resolve?: boolean;\n administrativeUserId?: string | null;\n};\n\n/******\n * Payment Plan Types\n ******/\n\nexport type DebtorsPaymentPlan = {\n id: string;\n debtorDossierId: string;\n\n notes: {\n content: string;\n createdAt: string;\n createdBy: string;\n }[];\n\n reminders?: {\n startDate: string; // ISO date string\n frequency: {\n every: number;\n period: 'days' | 'weeks' | 'months';\n };\n endCondition:\n | {\n endDate: string; // ISO date string\n }\n | {\n occurrences: number; // Number of reminders to send\n };\n };\n\n createdAt: string;\n createdBy: string;\n updatedAt: string;\n updatedBy: string;\n};\n\nexport type NewPaymentPlan = Omit<\n DebtorsPaymentPlan,\n 'id' | 'createdAt' | 'updatedAt' | 'createdBy' | 'updatedBy' | 'notes'\n> & { notes?: string };\n\nexport type UpdatePaymentPlan = Partial<Pick<DebtorsPaymentPlan, 'reminders'>> & {\n newNote?: string;\n};\n\n/******\n * Legal Dossier Types\n ******/\n\nexport enum LegalDossierStatus {\n ASSESSMENT = 'assessment',\n PRE_LEGAL_NOTICE = 'pre_legal_notice',\n SENT_TO_LAWYER = 'sent_to_lawyer',\n FILED = 'filed',\n IN_COURT = 'in_court',\n JUDGMENT = 'judgment',\n ENFORCEMENT = 'enforcement',\n SETTLEMENT = 'settlement',\n CLOSED_RECOVERED = 'closed_recovered',\n CLOSED_UNRECOVERABLE = 'closed_unrecoverable',\n ON_HOLD = 'on_hold',\n}\n\nexport type LegalDossier = {\n id: string;\n debtorDossierId: string;\n caseNumber?: string;\n courtDate?: string; // ISO date string (YYYY-MM-DD)\n vehicleReportedToPolice?: boolean;\n vehicleReportedToPoliceAt?: string; // ISO timestamp, stamped server-side\n notes?: string;\n createdAt: string;\n createdBy: string;\n updatedAt: string;\n updatedBy: string;\n status: LegalDossierStatus;\n};\n\nexport type NewLegalDossier = Omit<\n LegalDossier,\n 'id' | 'createdAt' | 'updatedAt' | 'createdBy' | 'updatedBy'\n>;\n\nexport type UpdateLegalDossier = Partial<\n Pick<LegalDossier, 'caseNumber' | 'courtDate' | 'status' | 'notes' | 'vehicleReportedToPolice'>\n>;\n\n/******\n * Debtor Dossier Events\n ******/\n\nexport type DebtorsDossierCreateEvent = {\n action: 'created';\n data: DebtorsDossier;\n previousData?: undefined;\n tenantId: string;\n userId: string;\n};\n\nexport type DebtorsDossierUpdateEvent = {\n action: 'updated';\n data: DebtorsDossier;\n previousData: DebtorsDossier;\n tenantId: string;\n userId: string;\n};\n\nexport type DebtorsDossierDeleteEvent = {\n action: 'deleted';\n data?: undefined;\n previousData: DebtorsDossier;\n tenantId: string;\n userId: string;\n};\n\nexport type DebtorsDossierEvent =\n | DebtorsDossierCreateEvent\n | DebtorsDossierUpdateEvent\n | DebtorsDossierDeleteEvent;\n\n/************\n *\n * Search\n */\n\nexport type SearchDebtorsDossier = {\n contact?: Contact;\n debtorsDossier: DebtorsDossier;\n org?: Organization;\n legalDossier?: LegalDossier;\n paymentPlan?: DebtorsPaymentPlan;\n hasPaymentPlan?: boolean;\n branchIds?: string[];\n tasks: {\n totalTasks: number;\n openTasks: number;\n nextDueAt?: string;\n };\n overdue: {\n riskLevel: number;\n riskLevelLabel?: string;\n remindersSent: number;\n hasActiveLdrs?: boolean;\n };\n /** One entry per tracked contract of the organization, copied from the contracts index. */\n mileage?: ContractMileage[];\n mileageSummary?: MileageSummary;\n};\n\n/************\n *\n * Kanban\n */\n\nexport type DebtorsDossierKanbanColumn = {\n status: DebtorsDossierStatus;\n results: SearchDebtorsDossier[];\n totalCount: number;\n totalValue: string;\n};\n\nexport type MSearchDebtorsDossierKanbanColumn = {\n column: DebtorsDossierKanbanColumn;\n nextToken?: string;\n};\n\nexport type KanbanDebtorsDossierSearchRequest = BaseSearchRequest & {\n nextTokens?: Record<string, string | undefined>;\n statusSortBy?: Record<DebtorsDossierStatus, { fieldId: string; order: SortOrder }[]>;\n};\n\nexport type KanbanDebtorsDossierNextList = Omit<\n NextList<DebtorsDossierKanbanColumn, ReferenceData>,\n 'nextToken'\n> & {\n nextTokens?: Record<string, string | undefined>;\n};\n\nexport const DebtorsDossierStatusOrder: DebtorsDossierStatus[] = [\n DebtorsDossierStatus.AUTO_REMINDER,\n DebtorsDossierStatus.OVERDUE,\n DebtorsDossierStatus.CONTACT_ATTEMPTED,\n DebtorsDossierStatus.DIALOGUE,\n DebtorsDossierStatus.PROMISE_TO_PAY,\n DebtorsDossierStatus.FAILURE,\n];\n\nexport const DebtorsDossierWonColumnId = DebtorsDossierStatus.RESOLVED;\n\nexport const DebtorsDossierKanbanEndColumns: DebtorsDossierStatus[] = [\n DebtorsDossierStatus.RESOLVED,\n];\n\nexport const DebtorsDossierKanbanColumns = [\n ...DebtorsDossierStatusOrder,\n ...DebtorsDossierKanbanEndColumns,\n];\n"]}
|
|
@@ -2,6 +2,7 @@ import { InsuranceEntry } from '@bisondesk/commons-sdk/insurance';
|
|
|
2
2
|
import { Contact, Organization } from './crm.js';
|
|
3
3
|
import { PublicSearchDefinition } from './definitions.js';
|
|
4
4
|
import { LeasingContract } from './leasing.js';
|
|
5
|
+
import { ContractMileage } from './mileage.js';
|
|
5
6
|
import { Vehicle } from './vehicles.js';
|
|
6
7
|
export type LeasingPublicSearchDefinitions = {
|
|
7
8
|
searchLeasingContract: PublicSearchDefinition;
|
|
@@ -24,6 +25,7 @@ export type SearchLeasingContract = {
|
|
|
24
25
|
supplierName?: string;
|
|
25
26
|
hasActiveRecurrence?: boolean;
|
|
26
27
|
lastRecurrenceRunAt?: string;
|
|
28
|
+
mileage?: ContractMileage;
|
|
27
29
|
};
|
|
28
30
|
};
|
|
29
31
|
export type InputSearchLeasingContract = SearchLeasingContract;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leasing-search.d.ts","sourceRoot":"/","sources":["types/leasing-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,8BAA8B,GAAG;IAC3C,qBAAqB,EAAE,sBAAsB,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,OAAO,EAAE,sBAAsB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B,GAAG,EAAE,YAAY,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE;QACN,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,cAAc,CAAC;QAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"leasing-search.d.ts","sourceRoot":"/","sources":["types/leasing-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,MAAM,8BAA8B,GAAG;IAC3C,qBAAqB,EAAE,sBAAsB,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,OAAO,EAAE,sBAAsB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B,GAAG,EAAE,YAAY,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE;QACN,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,CAAC,EAAE,cAAc,CAAC;QAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,OAAO,CAAC,EAAE,eAAe,CAAC;KAC3B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,qBAAqB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"leasing-search.js","sourceRoot":"/","sources":["types/leasing-search.ts"],"names":[],"mappings":"","sourcesContent":["import { InsuranceEntry } from '@bisondesk/commons-sdk/insurance';\nimport { Contact, Organization } from './crm.js';\nimport { PublicSearchDefinition } from './definitions.js';\nimport { LeasingContract } from './leasing.js';\nimport { Vehicle } from './vehicles.js';\n\nexport type LeasingPublicSearchDefinitions = {\n searchLeasingContract: PublicSearchDefinition;\n};\n\nexport type LeasingDebtorsSearchDefinitions = {\n debtors: PublicSearchDefinition;\n};\n\nexport type SearchLeasingContract = {\n contract: LeasingContract;\n org: Organization;\n contact?: Contact;\n vehicle: Vehicle;\n custom: {\n active: boolean;\n insurance?: InsuranceEntry;\n externalTracking?: boolean;\n accountManager?: string;\n lastIssuedInvoiceDate?: string;\n dealRating?: number;\n supplierName?: string;\n hasActiveRecurrence?: boolean;\n lastRecurrenceRunAt?: string;\n };\n};\n\nexport type InputSearchLeasingContract = SearchLeasingContract;\n"]}
|
|
1
|
+
{"version":3,"file":"leasing-search.js","sourceRoot":"/","sources":["types/leasing-search.ts"],"names":[],"mappings":"","sourcesContent":["import { InsuranceEntry } from '@bisondesk/commons-sdk/insurance';\nimport { Contact, Organization } from './crm.js';\nimport { PublicSearchDefinition } from './definitions.js';\nimport { LeasingContract } from './leasing.js';\nimport { ContractMileage } from './mileage.js';\nimport { Vehicle } from './vehicles.js';\n\nexport type LeasingPublicSearchDefinitions = {\n searchLeasingContract: PublicSearchDefinition;\n};\n\nexport type LeasingDebtorsSearchDefinitions = {\n debtors: PublicSearchDefinition;\n};\n\nexport type SearchLeasingContract = {\n contract: LeasingContract;\n org: Organization;\n contact?: Contact;\n vehicle: Vehicle;\n custom: {\n active: boolean;\n insurance?: InsuranceEntry;\n externalTracking?: boolean;\n accountManager?: string;\n lastIssuedInvoiceDate?: string;\n dealRating?: number;\n supplierName?: string;\n hasActiveRecurrence?: boolean;\n lastRecurrenceRunAt?: string;\n mileage?: ContractMileage;\n };\n};\n\nexport type InputSearchLeasingContract = SearchLeasingContract;\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare enum MileageStatus {
|
|
2
|
+
NoSignal = "no-signal",
|
|
3
|
+
TooEarly = "too-early",
|
|
4
|
+
Low = "low",
|
|
5
|
+
Normal = "normal",
|
|
6
|
+
High = "high"
|
|
7
|
+
}
|
|
8
|
+
export type MileageAlert = MileageStatus.Low | MileageStatus.High | MileageStatus.NoSignal;
|
|
9
|
+
export declare enum MileageTrendDirection {
|
|
10
|
+
Up = "up",
|
|
11
|
+
Down = "down",
|
|
12
|
+
Flat = "flat"
|
|
13
|
+
}
|
|
14
|
+
export type MileageTrend = {
|
|
15
|
+
direction: MileageTrendDirection;
|
|
16
|
+
percent: number;
|
|
17
|
+
};
|
|
18
|
+
export type ContractMileage = {
|
|
19
|
+
contractId: string;
|
|
20
|
+
stockNumber?: string;
|
|
21
|
+
status: MileageStatus;
|
|
22
|
+
alert?: MileageAlert;
|
|
23
|
+
last30DaysKm: number;
|
|
24
|
+
currentYearKm?: number;
|
|
25
|
+
yearAvg30DaysKm?: number;
|
|
26
|
+
trend?: MileageTrend;
|
|
27
|
+
lastReadingAt?: string;
|
|
28
|
+
};
|
|
29
|
+
export type MileageSummary = {
|
|
30
|
+
vehicles: number;
|
|
31
|
+
noSignal: number;
|
|
32
|
+
high: number;
|
|
33
|
+
low: number;
|
|
34
|
+
issues: number;
|
|
35
|
+
last30DaysKm?: number;
|
|
36
|
+
trend?: MileageTrend;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=mileage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mileage.d.ts","sourceRoot":"/","sources":["types/mileage.ts"],"names":[],"mappings":"AAAA,oBAAY,aAAa;IACvB,QAAQ,cAAc;IACtB,QAAQ,cAAc;IACtB,GAAG,QAAQ;IACX,MAAM,WAAW;IACjB,IAAI,SAAS;CACd;AAED,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC,GAAG,GAAG,aAAa,CAAC,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC;AAE3F,oBAAY,qBAAqB;IAC/B,EAAE,OAAO;IACT,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,qBAAqB,CAAC;IAEjC,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAGF,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,aAAa,CAAC;IAEtB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IAErB,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAGF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IAEjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export var MileageStatus;
|
|
2
|
+
(function (MileageStatus) {
|
|
3
|
+
MileageStatus["NoSignal"] = "no-signal";
|
|
4
|
+
MileageStatus["TooEarly"] = "too-early";
|
|
5
|
+
MileageStatus["Low"] = "low";
|
|
6
|
+
MileageStatus["Normal"] = "normal";
|
|
7
|
+
MileageStatus["High"] = "high";
|
|
8
|
+
})(MileageStatus || (MileageStatus = {}));
|
|
9
|
+
export var MileageTrendDirection;
|
|
10
|
+
(function (MileageTrendDirection) {
|
|
11
|
+
MileageTrendDirection["Up"] = "up";
|
|
12
|
+
MileageTrendDirection["Down"] = "down";
|
|
13
|
+
MileageTrendDirection["Flat"] = "flat";
|
|
14
|
+
})(MileageTrendDirection || (MileageTrendDirection = {}));
|
|
15
|
+
//# sourceMappingURL=mileage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mileage.js","sourceRoot":"/","sources":["types/mileage.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,aAMX;AAND,WAAY,aAAa;IACvB,uCAAsB,CAAA;IACtB,uCAAsB,CAAA;IACtB,4BAAW,CAAA;IACX,kCAAiB,CAAA;IACjB,8BAAa,CAAA;AACf,CAAC,EANW,aAAa,KAAb,aAAa,QAMxB;AAID,MAAM,CAAN,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,kCAAS,CAAA;IACT,sCAAa,CAAA;IACb,sCAAa,CAAA;AACf,CAAC,EAJW,qBAAqB,KAArB,qBAAqB,QAIhC","sourcesContent":["export enum MileageStatus {\n NoSignal = 'no-signal',\n TooEarly = 'too-early',\n Low = 'low',\n Normal = 'normal',\n High = 'high',\n}\n\nexport type MileageAlert = MileageStatus.Low | MileageStatus.High | MileageStatus.NoSignal;\n\nexport enum MileageTrendDirection {\n Up = 'up',\n Down = 'down',\n Flat = 'flat',\n}\n\nexport type MileageTrend = {\n direction: MileageTrendDirection;\n /** The last 30 days against the 12-month average, in percent. */\n percent: number;\n};\n\n/** Km driven by a contract's vehicle, read from its wired track-and-trace device. */\nexport type ContractMileage = {\n contractId: string;\n stockNumber?: string;\n status: MileageStatus;\n /** The status, when it is outside the limits and the contract has overdue invoices. */\n alert?: MileageAlert;\n last30DaysKm: number;\n /** Absent while the device document predates the yearly figures: unknown, not zero. */\n currentYearKm?: number;\n /** Km per 30 days over the past 12 months; absent under 60 tracked days. */\n yearAvg30DaysKm?: number;\n trend?: MileageTrend;\n lastReadingAt?: string;\n};\n\n/** A debtor dossier's tracked vehicles at a glance, for the dossier lists and boards. */\nexport type MileageSummary = {\n vehicles: number;\n /** Vehicles flagged per alert: outside the limits on a contract with overdue invoices. */\n noSignal: number;\n high: number;\n low: number;\n issues: number;\n /** Km over the last 30 days of the vehicles still reporting; absent when none is. */\n last30DaysKm?: number;\n /** Those vehicles' km against their combined 12-month average. */\n trend?: MileageTrend;\n};\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ContractMileage, MileageAlert, MileageStatus, MileageSummary, MileageTrend } from '../types/mileage.js';
|
|
2
|
+
export declare const MILEAGE_LOW_KM_30_DAYS = 250;
|
|
3
|
+
export declare const MILEAGE_TREND_BAND = 0.15;
|
|
4
|
+
export declare const KM_FILTER_MAX = 15000;
|
|
5
|
+
export declare const KM_FILTER_STEP = 250;
|
|
6
|
+
export declare const MILEAGE_HIGH_KM_30_DAYS: {
|
|
7
|
+
[category: string]: number;
|
|
8
|
+
};
|
|
9
|
+
export declare const getMileageStatus: (input: {
|
|
10
|
+
category?: string;
|
|
11
|
+
last30DaysKm: number;
|
|
12
|
+
lastReadingAt?: string;
|
|
13
|
+
trackedSince?: string;
|
|
14
|
+
}, now?: Date) => MileageStatus;
|
|
15
|
+
export declare const getMileageAlert: (status: MileageStatus, overdue: boolean) => MileageAlert | undefined;
|
|
16
|
+
export declare const getMileageTrend: (last30DaysKm: number, yearAvg30DaysKm: number | undefined) => MileageTrend | undefined;
|
|
17
|
+
export declare const getMileageSummary: (mileage: ContractMileage[]) => MileageSummary;
|
|
18
|
+
//# sourceMappingURL=mileage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mileage.d.ts","sourceRoot":"/","sources":["utils/mileage.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,eAAe,EACf,YAAY,EACZ,aAAa,EACb,cAAc,EACd,YAAY,EAEb,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,eAAO,MAAM,aAAa,QAAS,CAAC;AACpC,eAAO,MAAM,cAAc,MAAM,CAAC;AAKlC,eAAO,MAAM,uBAAuB,EAAE;IAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAKjE,CAAC;AAMF,eAAO,MAAM,gBAAgB,UACpB;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,QAC5F,IAAI,KACR,aAqBF,CAAC;AAQF,eAAO,MAAM,eAAe,WAClB,aAAa,WACZ,OAAO,KACf,YAAY,GAAG,SAAsE,CAAC;AAEzF,eAAO,MAAM,eAAe,iBACZ,MAAM,mBACH,MAAM,GAAG,SAAS,KAClC,YAAY,GAAG,SAajB,CAAC;AAMF,eAAO,MAAM,iBAAiB,YAAa,eAAe,EAAE,KAAG,cAoB9D,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { differenceInCalendarDays, parseISO } from 'date-fns';
|
|
2
|
+
import { sumBy } from 'lodash-es';
|
|
3
|
+
import { Categories } from '../constants.js';
|
|
4
|
+
import { MileageStatus, MileageTrendDirection, } from '../types/mileage.js';
|
|
5
|
+
export const MILEAGE_LOW_KM_30_DAYS = 250;
|
|
6
|
+
export const MILEAGE_TREND_BAND = 0.15;
|
|
7
|
+
export const KM_FILTER_MAX = 15_000;
|
|
8
|
+
export const KM_FILTER_STEP = 250;
|
|
9
|
+
const MILEAGE_WINDOW_DAYS = 30;
|
|
10
|
+
const MILEAGE_SIGNAL_LOST_AFTER_DAYS = 3;
|
|
11
|
+
export const MILEAGE_HIGH_KM_30_DAYS = {
|
|
12
|
+
[Categories.Van]: 7_500,
|
|
13
|
+
[Categories.Car]: 7_500,
|
|
14
|
+
[Categories.TractorHead]: 12_000,
|
|
15
|
+
[Categories.Truck]: 12_000,
|
|
16
|
+
};
|
|
17
|
+
export const getMileageStatus = (input, now = new Date()) => {
|
|
18
|
+
if (input.lastReadingAt == null ||
|
|
19
|
+
differenceInCalendarDays(now, parseISO(input.lastReadingAt)) > MILEAGE_SIGNAL_LOST_AFTER_DAYS) {
|
|
20
|
+
return MileageStatus.NoSignal;
|
|
21
|
+
}
|
|
22
|
+
if (input.trackedSince != null &&
|
|
23
|
+
differenceInCalendarDays(now, parseISO(input.trackedSince)) < MILEAGE_WINDOW_DAYS) {
|
|
24
|
+
return MileageStatus.TooEarly;
|
|
25
|
+
}
|
|
26
|
+
if (input.last30DaysKm < MILEAGE_LOW_KM_30_DAYS) {
|
|
27
|
+
return MileageStatus.Low;
|
|
28
|
+
}
|
|
29
|
+
const highLimit = input.category != null ? MILEAGE_HIGH_KM_30_DAYS[input.category] : undefined;
|
|
30
|
+
if (highLimit != null && input.last30DaysKm > highLimit) {
|
|
31
|
+
return MileageStatus.High;
|
|
32
|
+
}
|
|
33
|
+
return MileageStatus.Normal;
|
|
34
|
+
};
|
|
35
|
+
const isOutsideLimits = (status) => status === MileageStatus.Low ||
|
|
36
|
+
status === MileageStatus.High ||
|
|
37
|
+
status === MileageStatus.NoSignal;
|
|
38
|
+
export const getMileageAlert = (status, overdue) => (overdue && isOutsideLimits(status) ? status : undefined);
|
|
39
|
+
export const getMileageTrend = (last30DaysKm, yearAvg30DaysKm) => {
|
|
40
|
+
if (yearAvg30DaysKm == null || yearAvg30DaysKm === 0) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const change = (last30DaysKm - yearAvg30DaysKm) / yearAvg30DaysKm;
|
|
44
|
+
const percent = Math.round(change * 100);
|
|
45
|
+
if (change >= MILEAGE_TREND_BAND) {
|
|
46
|
+
return { direction: MileageTrendDirection.Up, percent };
|
|
47
|
+
}
|
|
48
|
+
if (change <= -MILEAGE_TREND_BAND) {
|
|
49
|
+
return { direction: MileageTrendDirection.Down, percent };
|
|
50
|
+
}
|
|
51
|
+
return { direction: MileageTrendDirection.Flat, percent };
|
|
52
|
+
};
|
|
53
|
+
export const getMileageSummary = (mileage) => {
|
|
54
|
+
const countAlert = (alert) => mileage.filter((item) => item.alert === alert).length;
|
|
55
|
+
const noSignal = countAlert(MileageStatus.NoSignal);
|
|
56
|
+
const high = countAlert(MileageStatus.High);
|
|
57
|
+
const low = countAlert(MileageStatus.Low);
|
|
58
|
+
const reporting = mileage.filter((item) => item.status !== MileageStatus.NoSignal);
|
|
59
|
+
const withAverage = reporting.filter((item) => item.yearAvg30DaysKm != null);
|
|
60
|
+
return {
|
|
61
|
+
vehicles: mileage.length,
|
|
62
|
+
noSignal,
|
|
63
|
+
high,
|
|
64
|
+
low,
|
|
65
|
+
issues: noSignal + high + low,
|
|
66
|
+
last30DaysKm: reporting.length > 0 ? sumBy(reporting, (item) => item.last30DaysKm) : undefined,
|
|
67
|
+
trend: getMileageTrend(sumBy(withAverage, (item) => item.last30DaysKm), sumBy(withAverage, (item) => item.yearAvg30DaysKm ?? 0)),
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=mileage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mileage.js","sourceRoot":"/","sources":["utils/mileage.ts"],"names":[],"mappings":"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","sourcesContent":["import { differenceInCalendarDays, parseISO } from 'date-fns';\nimport { sumBy } from 'lodash-es';\nimport { Categories } from '../constants.js';\nimport {\n ContractMileage,\n MileageAlert,\n MileageStatus,\n MileageSummary,\n MileageTrend,\n MileageTrendDirection,\n} from '../types/mileage.js';\n\nexport const MILEAGE_LOW_KM_30_DAYS = 250;\nexport const MILEAGE_TREND_BAND = 0.15;\nexport const KM_FILTER_MAX = 15_000;\nexport const KM_FILTER_STEP = 250;\n\nconst MILEAGE_WINDOW_DAYS = 30;\nconst MILEAGE_SIGNAL_LOST_AFTER_DAYS = 3;\n\nexport const MILEAGE_HIGH_KM_30_DAYS: { [category: string]: number } = {\n [Categories.Van]: 7_500,\n [Categories.Car]: 7_500,\n [Categories.TractorHead]: 12_000,\n [Categories.Truck]: 12_000,\n};\n\n/**\n * A device that has not reported for more than three days, or never did, has no signal: its km\n * figures stop refreshing, so they say nothing about how much the vehicle drives.\n */\nexport const getMileageStatus = (\n input: { category?: string; last30DaysKm: number; lastReadingAt?: string; trackedSince?: string },\n now: Date = new Date(),\n): MileageStatus => {\n if (\n input.lastReadingAt == null ||\n differenceInCalendarDays(now, parseISO(input.lastReadingAt)) > MILEAGE_SIGNAL_LOST_AFTER_DAYS\n ) {\n return MileageStatus.NoSignal;\n }\n if (\n input.trackedSince != null &&\n differenceInCalendarDays(now, parseISO(input.trackedSince)) < MILEAGE_WINDOW_DAYS\n ) {\n return MileageStatus.TooEarly;\n }\n if (input.last30DaysKm < MILEAGE_LOW_KM_30_DAYS) {\n return MileageStatus.Low;\n }\n const highLimit = input.category != null ? MILEAGE_HIGH_KM_30_DAYS[input.category] : undefined;\n if (highLimit != null && input.last30DaysKm > highLimit) {\n return MileageStatus.High;\n }\n return MileageStatus.Normal;\n};\n\nconst isOutsideLimits = (status: MileageStatus): status is MileageAlert =>\n status === MileageStatus.Low ||\n status === MileageStatus.High ||\n status === MileageStatus.NoSignal;\n\n/** Debt follow-up only cares about mileage outside the limits on a contract that is overdue. */\nexport const getMileageAlert = (\n status: MileageStatus,\n overdue: boolean,\n): MileageAlert | undefined => (overdue && isOutsideLimits(status) ? status : undefined);\n\nexport const getMileageTrend = (\n last30DaysKm: number,\n yearAvg30DaysKm: number | undefined,\n): MileageTrend | undefined => {\n if (yearAvg30DaysKm == null || yearAvg30DaysKm === 0) {\n return undefined;\n }\n const change = (last30DaysKm - yearAvg30DaysKm) / yearAvg30DaysKm;\n const percent = Math.round(change * 100);\n if (change >= MILEAGE_TREND_BAND) {\n return { direction: MileageTrendDirection.Up, percent };\n }\n if (change <= -MILEAGE_TREND_BAND) {\n return { direction: MileageTrendDirection.Down, percent };\n }\n return { direction: MileageTrendDirection.Flat, percent };\n};\n\n/**\n * Counts a dossier's flagged vehicles and adds up the km of the ones still reporting. A silent\n * device's figures stay frozen at its last reading, so they are left out of the total and the trend.\n */\nexport const getMileageSummary = (mileage: ContractMileage[]): MileageSummary => {\n const countAlert = (alert: MileageAlert) => mileage.filter((item) => item.alert === alert).length;\n const noSignal = countAlert(MileageStatus.NoSignal);\n const high = countAlert(MileageStatus.High);\n const low = countAlert(MileageStatus.Low);\n const reporting = mileage.filter((item) => item.status !== MileageStatus.NoSignal);\n const withAverage = reporting.filter((item) => item.yearAvg30DaysKm != null);\n\n return {\n vehicles: mileage.length,\n noSignal,\n high,\n low,\n issues: noSignal + high + low,\n last30DaysKm: reporting.length > 0 ? sumBy(reporting, (item) => item.last30DaysKm) : undefined,\n trend: getMileageTrend(\n sumBy(withAverage, (item) => item.last30DaysKm),\n sumBy(withAverage, (item) => item.yearAvg30DaysKm ?? 0),\n ),\n };\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mileage.test.d.ts","sourceRoot":"/","sources":["utils/mileage.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { Categories } from '../constants.js';
|
|
3
|
+
import { MileageStatus, MileageTrendDirection } from '../types/mileage.js';
|
|
4
|
+
import { getMileageAlert, getMileageStatus, getMileageSummary, getMileageTrend, } from './mileage.js';
|
|
5
|
+
const now = new Date('2026-09-30T12:00:00Z');
|
|
6
|
+
const lastReadingAt = '2026-09-30T06:00:00Z';
|
|
7
|
+
describe('getMileageStatus', () => {
|
|
8
|
+
test.each([
|
|
9
|
+
{ name: 'silent for more than three days', lastReadingAt: '2026-09-26T09:00:00Z' },
|
|
10
|
+
{ name: 'that never reported', lastReadingAt: undefined },
|
|
11
|
+
])('a device $name has no signal, whatever its last figures say', ({ lastReadingAt }) => {
|
|
12
|
+
expect(getMileageStatus({ category: Categories.Van, last30DaysKm: 8_950, lastReadingAt }, now)).toBe(MileageStatus.NoSignal);
|
|
13
|
+
});
|
|
14
|
+
test('a device quiet for three days still has a signal', () => {
|
|
15
|
+
expect(getMileageStatus({ category: Categories.Van, last30DaysKm: 3_000, lastReadingAt: '2026-09-27T09:00:00Z' }, now)).toBe(MileageStatus.Normal);
|
|
16
|
+
});
|
|
17
|
+
test('a device installed less than 30 days ago is too early to judge', () => {
|
|
18
|
+
expect(getMileageStatus({ last30DaysKm: 40, lastReadingAt, trackedSince: '2026-09-15T08:00:00Z' }, now)).toBe(MileageStatus.TooEarly);
|
|
19
|
+
});
|
|
20
|
+
test.each([
|
|
21
|
+
{ category: Categories.Van, last30DaysKm: 249, expected: MileageStatus.Low },
|
|
22
|
+
{ category: Categories.Van, last30DaysKm: 250, expected: MileageStatus.Normal },
|
|
23
|
+
{ category: Categories.Van, last30DaysKm: 7_500, expected: MileageStatus.Normal },
|
|
24
|
+
{ category: Categories.Van, last30DaysKm: 7_501, expected: MileageStatus.High },
|
|
25
|
+
{ category: Categories.Car, last30DaysKm: 7_501, expected: MileageStatus.High },
|
|
26
|
+
{ category: Categories.TractorHead, last30DaysKm: 12_000, expected: MileageStatus.Normal },
|
|
27
|
+
{ category: Categories.TractorHead, last30DaysKm: 12_001, expected: MileageStatus.High },
|
|
28
|
+
{ category: Categories.Truck, last30DaysKm: 12_001, expected: MileageStatus.High },
|
|
29
|
+
{ category: Categories.Machine, last30DaysKm: 50_000, expected: MileageStatus.Normal },
|
|
30
|
+
{ category: undefined, last30DaysKm: 50_000, expected: MileageStatus.Normal },
|
|
31
|
+
])('$category at $last30DaysKm km is $expected', ({ category, last30DaysKm, expected }) => {
|
|
32
|
+
expect(getMileageStatus({ category, last30DaysKm, lastReadingAt, trackedSince: '2025-01-01T00:00:00Z' }, now)).toBe(expected);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('getMileageAlert', () => {
|
|
36
|
+
test.each([
|
|
37
|
+
MileageStatus.Low,
|
|
38
|
+
MileageStatus.High,
|
|
39
|
+
MileageStatus.NoSignal,
|
|
40
|
+
])('%s on an overdue contract is an alert', (status) => {
|
|
41
|
+
expect(getMileageAlert(status, true)).toBe(status);
|
|
42
|
+
});
|
|
43
|
+
test.each([MileageStatus.Normal, MileageStatus.TooEarly])('%s is never an alert', (status) => {
|
|
44
|
+
expect(getMileageAlert(status, true)).toBeUndefined();
|
|
45
|
+
});
|
|
46
|
+
test('a contract without overdue invoices has no alert', () => {
|
|
47
|
+
expect(getMileageAlert(MileageStatus.Low, false)).toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('getMileageTrend', () => {
|
|
51
|
+
test('has no trend without a yearly average', () => {
|
|
52
|
+
expect(getMileageTrend(1_000, undefined)).toBeUndefined();
|
|
53
|
+
expect(getMileageTrend(1_000, 0)).toBeUndefined();
|
|
54
|
+
});
|
|
55
|
+
test.each([
|
|
56
|
+
{ last30DaysKm: 13_200, direction: MileageTrendDirection.Up, percent: 32 },
|
|
57
|
+
{ last30DaysKm: 11_500, direction: MileageTrendDirection.Up, percent: 15 },
|
|
58
|
+
{ last30DaysKm: 11_400, direction: MileageTrendDirection.Flat, percent: 14 },
|
|
59
|
+
{ last30DaysKm: 8_600, direction: MileageTrendDirection.Flat, percent: -14 },
|
|
60
|
+
{ last30DaysKm: 8_500, direction: MileageTrendDirection.Down, percent: -15 },
|
|
61
|
+
{ last30DaysKm: 300, direction: MileageTrendDirection.Down, percent: -97 },
|
|
62
|
+
])('$last30DaysKm km against 10 000 is $direction $percent%', ({ last30DaysKm, direction, percent, }) => {
|
|
63
|
+
expect(getMileageTrend(last30DaysKm, 10_000)).toEqual({ direction, percent });
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('getMileageSummary', () => {
|
|
67
|
+
const vehicle = (contractId, status, alert, last30DaysKm, yearAvg30DaysKm) => ({ contractId, status, alert, last30DaysKm, yearAvg30DaysKm });
|
|
68
|
+
test('counts flagged vehicles per alert and leaves silent devices out of the km', () => {
|
|
69
|
+
expect(getMileageSummary([
|
|
70
|
+
vehicle('a', MileageStatus.NoSignal, MileageStatus.NoSignal, 9_000, 9_000),
|
|
71
|
+
vehicle('b', MileageStatus.NoSignal, undefined, 4_000),
|
|
72
|
+
vehicle('c', MileageStatus.High, MileageStatus.High, 13_000, 10_000),
|
|
73
|
+
vehicle('d', MileageStatus.Low, MileageStatus.Low, 100, 2_000),
|
|
74
|
+
vehicle('e', MileageStatus.Low, undefined, 200),
|
|
75
|
+
vehicle('f', MileageStatus.TooEarly, undefined, 1_500),
|
|
76
|
+
])).toEqual({
|
|
77
|
+
vehicles: 6,
|
|
78
|
+
noSignal: 1,
|
|
79
|
+
high: 1,
|
|
80
|
+
low: 1,
|
|
81
|
+
issues: 3,
|
|
82
|
+
last30DaysKm: 14_800,
|
|
83
|
+
trend: { direction: MileageTrendDirection.Flat, percent: 9 },
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
test('has no km and no trend when no device is reporting', () => {
|
|
87
|
+
const summary = getMileageSummary([
|
|
88
|
+
vehicle('a', MileageStatus.NoSignal, MileageStatus.NoSignal, 9_000, 9_000),
|
|
89
|
+
]);
|
|
90
|
+
expect(summary.last30DaysKm).toBeUndefined();
|
|
91
|
+
expect(summary.trend).toBeUndefined();
|
|
92
|
+
});
|
|
93
|
+
test('is all zeros for a dossier without tracked vehicles', () => {
|
|
94
|
+
expect(getMileageSummary([])).toEqual({
|
|
95
|
+
vehicles: 0,
|
|
96
|
+
noSignal: 0,
|
|
97
|
+
high: 0,
|
|
98
|
+
low: 0,
|
|
99
|
+
issues: 0,
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
//# sourceMappingURL=mileage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mileage.test.js","sourceRoot":"/","sources":["utils/mileage.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test } from 'vitest';\nimport { Categories } from '../constants.js';\nimport { ContractMileage, MileageStatus, MileageTrendDirection } from '../types/mileage.js';\nimport {\n getMileageAlert,\n getMileageStatus,\n getMileageSummary,\n getMileageTrend,\n} from './mileage.js';\n\nconst now = new Date('2026-09-30T12:00:00Z');\nconst lastReadingAt = '2026-09-30T06:00:00Z';\n\ndescribe('getMileageStatus', () => {\n test.each([\n { name: 'silent for more than three days', lastReadingAt: '2026-09-26T09:00:00Z' },\n { name: 'that never reported', lastReadingAt: undefined },\n ])('a device $name has no signal, whatever its last figures say', ({ lastReadingAt }) => {\n expect(\n getMileageStatus({ category: Categories.Van, last30DaysKm: 8_950, lastReadingAt }, now),\n ).toBe(MileageStatus.NoSignal);\n });\n\n test('a device quiet for three days still has a signal', () => {\n expect(\n getMileageStatus(\n { category: Categories.Van, last30DaysKm: 3_000, lastReadingAt: '2026-09-27T09:00:00Z' },\n now,\n ),\n ).toBe(MileageStatus.Normal);\n });\n\n test('a device installed less than 30 days ago is too early to judge', () => {\n expect(\n getMileageStatus(\n { last30DaysKm: 40, lastReadingAt, trackedSince: '2026-09-15T08:00:00Z' },\n now,\n ),\n ).toBe(MileageStatus.TooEarly);\n });\n\n test.each([\n { category: Categories.Van, last30DaysKm: 249, expected: MileageStatus.Low },\n { category: Categories.Van, last30DaysKm: 250, expected: MileageStatus.Normal },\n { category: Categories.Van, last30DaysKm: 7_500, expected: MileageStatus.Normal },\n { category: Categories.Van, last30DaysKm: 7_501, expected: MileageStatus.High },\n { category: Categories.Car, last30DaysKm: 7_501, expected: MileageStatus.High },\n { category: Categories.TractorHead, last30DaysKm: 12_000, expected: MileageStatus.Normal },\n { category: Categories.TractorHead, last30DaysKm: 12_001, expected: MileageStatus.High },\n { category: Categories.Truck, last30DaysKm: 12_001, expected: MileageStatus.High },\n { category: Categories.Machine, last30DaysKm: 50_000, expected: MileageStatus.Normal },\n { category: undefined, last30DaysKm: 50_000, expected: MileageStatus.Normal },\n ])('$category at $last30DaysKm km is $expected', ({ category, last30DaysKm, expected }) => {\n expect(\n getMileageStatus(\n { category, last30DaysKm, lastReadingAt, trackedSince: '2025-01-01T00:00:00Z' },\n now,\n ),\n ).toBe(expected);\n });\n});\n\ndescribe('getMileageAlert', () => {\n test.each([\n MileageStatus.Low,\n MileageStatus.High,\n MileageStatus.NoSignal,\n ])('%s on an overdue contract is an alert', (status) => {\n expect(getMileageAlert(status, true)).toBe(status);\n });\n\n test.each([MileageStatus.Normal, MileageStatus.TooEarly])('%s is never an alert', (status) => {\n expect(getMileageAlert(status, true)).toBeUndefined();\n });\n\n test('a contract without overdue invoices has no alert', () => {\n expect(getMileageAlert(MileageStatus.Low, false)).toBeUndefined();\n });\n});\n\ndescribe('getMileageTrend', () => {\n test('has no trend without a yearly average', () => {\n expect(getMileageTrend(1_000, undefined)).toBeUndefined();\n expect(getMileageTrend(1_000, 0)).toBeUndefined();\n });\n\n test.each([\n { last30DaysKm: 13_200, direction: MileageTrendDirection.Up, percent: 32 },\n { last30DaysKm: 11_500, direction: MileageTrendDirection.Up, percent: 15 },\n { last30DaysKm: 11_400, direction: MileageTrendDirection.Flat, percent: 14 },\n { last30DaysKm: 8_600, direction: MileageTrendDirection.Flat, percent: -14 },\n { last30DaysKm: 8_500, direction: MileageTrendDirection.Down, percent: -15 },\n { last30DaysKm: 300, direction: MileageTrendDirection.Down, percent: -97 },\n ])('$last30DaysKm km against 10 000 is $direction $percent%', ({\n last30DaysKm,\n direction,\n percent,\n }) => {\n expect(getMileageTrend(last30DaysKm, 10_000)).toEqual({ direction, percent });\n });\n});\n\ndescribe('getMileageSummary', () => {\n const vehicle = (\n contractId: string,\n status: MileageStatus,\n alert: ContractMileage['alert'],\n last30DaysKm: number,\n yearAvg30DaysKm?: number,\n ): ContractMileage => ({ contractId, status, alert, last30DaysKm, yearAvg30DaysKm });\n\n test('counts flagged vehicles per alert and leaves silent devices out of the km', () => {\n expect(\n getMileageSummary([\n vehicle('a', MileageStatus.NoSignal, MileageStatus.NoSignal, 9_000, 9_000),\n vehicle('b', MileageStatus.NoSignal, undefined, 4_000),\n vehicle('c', MileageStatus.High, MileageStatus.High, 13_000, 10_000),\n vehicle('d', MileageStatus.Low, MileageStatus.Low, 100, 2_000),\n vehicle('e', MileageStatus.Low, undefined, 200),\n vehicle('f', MileageStatus.TooEarly, undefined, 1_500),\n ]),\n ).toEqual({\n vehicles: 6,\n noSignal: 1,\n high: 1,\n low: 1,\n issues: 3,\n last30DaysKm: 14_800,\n trend: { direction: MileageTrendDirection.Flat, percent: 9 },\n });\n });\n\n test('has no km and no trend when no device is reporting', () => {\n const summary = getMileageSummary([\n vehicle('a', MileageStatus.NoSignal, MileageStatus.NoSignal, 9_000, 9_000),\n ]);\n\n expect(summary.last30DaysKm).toBeUndefined();\n expect(summary.trend).toBeUndefined();\n });\n\n test('is all zeros for a dossier without tracked vehicles', () => {\n expect(getMileageSummary([])).toEqual({\n vehicles: 0,\n noSignal: 0,\n high: 0,\n low: 0,\n issues: 0,\n });\n });\n});\n"]}
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@ import { EmailMessage } from '@bisondesk/commons-sdk/messages';
|
|
|
2
2
|
import { NextList, PaginatedList } from '@bisondesk/commons-sdk/types';
|
|
3
3
|
import { Contact, Organization } from './crm.js';
|
|
4
4
|
import { LeasingContract } from './leasing.js';
|
|
5
|
+
import { ContractMileage, MileageSummary } from './mileage.js';
|
|
5
6
|
import { BaseSearchRequest, SortFilter, SortOrder } from './search.js';
|
|
6
7
|
import { DataRecord, ReferenceData } from './utils.js';
|
|
7
8
|
|
|
@@ -342,6 +343,9 @@ export type SearchDebtorsDossier = {
|
|
|
342
343
|
remindersSent: number;
|
|
343
344
|
hasActiveLdrs?: boolean;
|
|
344
345
|
};
|
|
346
|
+
/** One entry per tracked contract of the organization, copied from the contracts index. */
|
|
347
|
+
mileage?: ContractMileage[];
|
|
348
|
+
mileageSummary?: MileageSummary;
|
|
345
349
|
};
|
|
346
350
|
|
|
347
351
|
/************
|
|
@@ -2,6 +2,7 @@ import { InsuranceEntry } from '@bisondesk/commons-sdk/insurance';
|
|
|
2
2
|
import { Contact, Organization } from './crm.js';
|
|
3
3
|
import { PublicSearchDefinition } from './definitions.js';
|
|
4
4
|
import { LeasingContract } from './leasing.js';
|
|
5
|
+
import { ContractMileage } from './mileage.js';
|
|
5
6
|
import { Vehicle } from './vehicles.js';
|
|
6
7
|
|
|
7
8
|
export type LeasingPublicSearchDefinitions = {
|
|
@@ -27,6 +28,7 @@ export type SearchLeasingContract = {
|
|
|
27
28
|
supplierName?: string;
|
|
28
29
|
hasActiveRecurrence?: boolean;
|
|
29
30
|
lastRecurrenceRunAt?: string;
|
|
31
|
+
mileage?: ContractMileage;
|
|
30
32
|
};
|
|
31
33
|
};
|
|
32
34
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export enum MileageStatus {
|
|
2
|
+
NoSignal = 'no-signal',
|
|
3
|
+
TooEarly = 'too-early',
|
|
4
|
+
Low = 'low',
|
|
5
|
+
Normal = 'normal',
|
|
6
|
+
High = 'high',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type MileageAlert = MileageStatus.Low | MileageStatus.High | MileageStatus.NoSignal;
|
|
10
|
+
|
|
11
|
+
export enum MileageTrendDirection {
|
|
12
|
+
Up = 'up',
|
|
13
|
+
Down = 'down',
|
|
14
|
+
Flat = 'flat',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type MileageTrend = {
|
|
18
|
+
direction: MileageTrendDirection;
|
|
19
|
+
/** The last 30 days against the 12-month average, in percent. */
|
|
20
|
+
percent: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Km driven by a contract's vehicle, read from its wired track-and-trace device. */
|
|
24
|
+
export type ContractMileage = {
|
|
25
|
+
contractId: string;
|
|
26
|
+
stockNumber?: string;
|
|
27
|
+
status: MileageStatus;
|
|
28
|
+
/** The status, when it is outside the limits and the contract has overdue invoices. */
|
|
29
|
+
alert?: MileageAlert;
|
|
30
|
+
last30DaysKm: number;
|
|
31
|
+
/** Absent while the device document predates the yearly figures: unknown, not zero. */
|
|
32
|
+
currentYearKm?: number;
|
|
33
|
+
/** Km per 30 days over the past 12 months; absent under 60 tracked days. */
|
|
34
|
+
yearAvg30DaysKm?: number;
|
|
35
|
+
trend?: MileageTrend;
|
|
36
|
+
lastReadingAt?: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** A debtor dossier's tracked vehicles at a glance, for the dossier lists and boards. */
|
|
40
|
+
export type MileageSummary = {
|
|
41
|
+
vehicles: number;
|
|
42
|
+
/** Vehicles flagged per alert: outside the limits on a contract with overdue invoices. */
|
|
43
|
+
noSignal: number;
|
|
44
|
+
high: number;
|
|
45
|
+
low: number;
|
|
46
|
+
issues: number;
|
|
47
|
+
/** Km over the last 30 days of the vehicles still reporting; absent when none is. */
|
|
48
|
+
last30DaysKm?: number;
|
|
49
|
+
/** Those vehicles' km against their combined 12-month average. */
|
|
50
|
+
trend?: MileageTrend;
|
|
51
|
+
};
|